Full Code of oceanprotocol/ocean.py for AI

main c7316103cdbc cached
195 files
662.9 KB
168.9k tokens
656 symbols
1 requests
Download .txt
Showing preview only (715K chars total). Download the full file or copy to clipboard to get everything.
Repository: oceanprotocol/ocean.py
Branch: main
Commit: c7316103cdbc
Files: 195
Total size: 662.9 KB

Directory structure:
gitextract_72imfimc/

├── .bumpversion.cfg
├── .codeclimate.yml
├── .copyright.tmpl
├── .coveragerc
├── .docignore
├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── black.yml
│       ├── build.yml
│       ├── libcheck.yml
│       ├── pytest.yml
│       └── release.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .prospector.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── READMEs/
│   ├── c2d-flow-more-examples.md
│   ├── c2d-flow.md
│   ├── custody-light-flow.md
│   ├── developers.md
│   ├── df.md
│   ├── gas-strategy-remote.md
│   ├── install.md
│   ├── key-value-private.md
│   ├── key-value-public.md
│   ├── main-flow.md
│   ├── parameters.md
│   ├── predict-eth.md
│   ├── profile-nfts-flow.md
│   ├── publish-flow-credentials.md
│   ├── publish-flow-graphql.md
│   ├── publish-flow-onchain.md
│   ├── publish-flow-restapi.md
│   ├── release-process.md
│   ├── search-and-filter-assets.md
│   ├── services.md
│   ├── setup-local.md
│   ├── setup-remote.md
│   └── using-clef.md
├── bumpversion.sh
├── conftest.py
├── conftest_ganache.py
├── ocean_lib/
│   ├── __init__.py
│   ├── agreements/
│   │   ├── __init__.py
│   │   ├── consumable.py
│   │   └── service_types.py
│   ├── aquarius/
│   │   ├── __init__.py
│   │   ├── aquarius.py
│   │   └── test/
│   │       ├── __init__.py
│   │       ├── conftest.py
│   │       └── test_aquarius.py
│   ├── assets/
│   │   ├── __init__.py
│   │   ├── asset_downloader.py
│   │   ├── credentials.py
│   │   ├── ddo.py
│   │   └── test/
│   │       ├── __init__.py
│   │       ├── conftest.py
│   │       ├── test_asset_downloader.py
│   │       └── test_ddo.py
│   ├── data_provider/
│   │   ├── __init__.py
│   │   ├── base.py
│   │   ├── data_encryptor.py
│   │   ├── data_service_provider.py
│   │   ├── fileinfo_provider.py
│   │   └── test/
│   │       ├── __init__.py
│   │       ├── conftest.py
│   │       ├── test_base.py
│   │       └── test_data_service_provider.py
│   ├── example_config.py
│   ├── exceptions.py
│   ├── http_requests/
│   │   ├── __init__.py
│   │   └── requests_session.py
│   ├── models/
│   │   ├── __init__.py
│   │   ├── compute_input.py
│   │   ├── data_nft.py
│   │   ├── data_nft_factory.py
│   │   ├── datatoken1.py
│   │   ├── datatoken2.py
│   │   ├── datatoken_base.py
│   │   ├── df/
│   │   │   ├── df_rewards.py
│   │   │   ├── df_strategy_v1.py
│   │   │   └── test/
│   │   │       ├── conftest.py
│   │   │       ├── test_df_rewards.py
│   │   │       └── test_df_strategy_v1.py
│   │   ├── dispenser.py
│   │   ├── erc721_token_factory_base.py
│   │   ├── factory_router.py
│   │   ├── fixed_rate_exchange.py
│   │   ├── test/
│   │   │   ├── __init__.py
│   │   │   ├── conftest.py
│   │   │   ├── test_data_nft.py
│   │   │   ├── test_data_nft_factory.py
│   │   │   ├── test_datatoken.py
│   │   │   ├── test_datatoken_order_both_templates.py
│   │   │   ├── test_dispenser.py
│   │   │   ├── test_exchange_fees.py
│   │   │   ├── test_exchange_main.py
│   │   │   ├── test_factory_router.py
│   │   │   └── test_fake_ocean.py
│   │   └── ve/
│   │       ├── smart_wallet_checker.py
│   │       ├── test/
│   │       │   ├── conftest.py
│   │       │   ├── test_smart_wallet_checker.py
│   │       │   ├── test_ve_allocate.py
│   │       │   ├── test_ve_delegation.py
│   │       │   ├── test_ve_fee_distributor.py
│   │       │   ├── test_ve_fee_estimate.py
│   │       │   └── test_ve_ocean.py
│   │       ├── ve_allocate.py
│   │       ├── ve_delegation.py
│   │       ├── ve_fee_distributor.py
│   │       ├── ve_fee_estimate.py
│   │       └── ve_ocean.py
│   ├── ocean/
│   │   ├── __init__.py
│   │   ├── crypto.py
│   │   ├── mint_fake_ocean.py
│   │   ├── ocean.py
│   │   ├── ocean_assets.py
│   │   ├── ocean_compute.py
│   │   ├── test/
│   │   │   ├── conftest.py
│   │   │   ├── test_crypto.py
│   │   │   ├── test_ocean.py
│   │   │   ├── test_ocean_assets.py
│   │   │   └── test_util.py
│   │   └── util.py
│   ├── services/
│   │   ├── consumer_parameters.py
│   │   ├── service.py
│   │   └── test/
│   │       ├── conftest.py
│   │       ├── test_consumer_parameters.py
│   │       └── test_service.py
│   ├── structures/
│   │   ├── abi_tuples.py
│   │   ├── algorithm_metadata.py
│   │   ├── file_objects.py
│   │   └── test/
│   │       ├── test_algorithm_metadata.py
│   │       └── test_file_objects.py
│   ├── test/
│   │   ├── __init__.py
│   │   ├── test_config.py
│   │   └── test_example_config.py
│   └── web3_internal/
│       ├── __init__.py
│       ├── clef.py
│       ├── constants.py
│       ├── contract_base.py
│       ├── contract_utils.py
│       ├── http_provider.py
│       ├── request.py
│       ├── test/
│       │   ├── __init__.py
│       │   ├── conftest.py
│       │   ├── test_contract_base.py
│       │   ├── test_contract_utils.py
│       │   └── test_wallet.py
│       └── utils.py
├── pyproject.toml
├── pytest.ini
├── requirements_dev.txt
├── setup.cfg
├── setup.py
└── tests/
    ├── __init__.py
    ├── flows/
    │   ├── __init__.py
    │   ├── conftest.py
    │   └── test_start_reuse_order_fees.py
    ├── generated-readmes/
    │   └── __init__.py
    ├── integration/
    │   ├── ganache/
    │   │   ├── conftest.py
    │   │   ├── test_compute_flow.py
    │   │   ├── test_consume_flow.py
    │   │   ├── test_disconnecting_components.py
    │   │   ├── test_graphql.py
    │   │   ├── test_market_flow.py
    │   │   └── test_onchain.py
    │   └── remote/
    │       ├── __init__.py
    │       ├── test_mumbai_main.py
    │       ├── test_mumbai_readme.py
    │       ├── test_polygon.py
    │       └── util.py
    ├── readmes/
    │   ├── conftest.py
    │   └── test_readmes.py
    └── resources/
        ├── __init__.py
        ├── ddo/
        │   ├── ddo_algorithm.json
        │   ├── ddo_algorithm2.json
        │   ├── ddo_sa_sample.json
        │   ├── ddo_sa_sample_disabled.json
        │   ├── ddo_sa_sample_with_credentials.json
        │   ├── ddo_sample_algorithm.json
        │   ├── ddo_v4_sample.json
        │   ├── ddo_v4_with_compute_service.json
        │   ├── ddo_v4_with_compute_service2.json
        │   ├── ddo_with_compute_service.json
        │   └── valid_metadata.json
        ├── ddo_helpers.py
        ├── helper_functions.py
        ├── keys/
        │   ├── key_file_1.json
        │   └── key_file_2.json
        ├── mocks/
        │   ├── __init__.py
        │   ├── data_provider_mock.py
        │   └── http_client_mock.py
        └── test/
            └── test_helper_functions.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .bumpversion.cfg
================================================
[bumpversion]
current_version = 3.1.2
commit = True
tag = True

[bumpversion:file:setup.py]
search = version='{current_version}'
replace = version='{new_version}'

[bumpversion:file:ocean_lib/__init__.py]
search = __version__ = '{current_version}'
replace = __version__ = '{new_version}'


================================================
FILE: .codeclimate.yml
================================================
##
## Copyright 2023 Ocean Protocol Foundation
## SPDX-License-Identifier: Apache-2.0
##
version: "2"
checks:
  argument-count:
    enabled: false
  file-lines:
    enabled: false
  complex-logic:
    enabled: false
  method-complexity:
    enabled: false
  method-count:
    enabled: false
  method-lines:
    enabled: false

================================================
FILE: .copyright.tmpl
================================================
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0


================================================
FILE: .coveragerc
================================================
[run]
omit = *test*


================================================
FILE: .docignore
================================================
**test**
CHANGELOG.md

================================================
FILE: .github/dependabot.yml
================================================
##
## Copyright 2023 Ocean Protocol Foundation
## SPDX-License-Identifier: Apache-2.0
##

# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
- package-ecosystem: pip
  directory: "/"
  schedule:
    interval: weekly
    time: '03:00'
    timezone: Europe/Berlin


================================================
FILE: .github/workflows/black.yml
================================================
##
## Copyright 2023 Ocean Protocol Foundation
## SPDX-License-Identifier: Apache-2.0
##
name: black

on: [push]

jobs:
  black:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: psf/black@stable
        with:
          options: "--check --verbose"
          version: "22.10.0"


================================================
FILE: .github/workflows/build.yml
================================================
##
## Copyright 2023 Ocean Protocol Foundation
## SPDX-License-Identifier: Apache-2.0
##
name: Ocean.py multiple OS

on:
  push:
    branches:
      - main
    tags:
      - '**'
  pull_request:
    branches:
      - '**'

jobs:
  build:
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        version: ['3.8', '3.10', '3.11']
    steps:
      - name: Setup Ocean.py
        uses: actions/checkout@v3
      - name: Set up Python ${{ matrix.version }}
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.version }}
      - name: Install pypa/build
        run: >-
          python -m
          pip install
          build
          --user
      - name: Build a binary wheel and a source tarball
        run: >-
          python -m
          build
          --sdist
          --wheel
          --outdir dist/
      - name: Install Mac OS specific dependencies
        if: ${{ matrix.os == 'macos-latest' }}
        run: |
          brew install autoconf automake libtool pkg-config
      - name: Install dependencies
        working-directory: ${{ github.workspace }}
        # vyper is grounded here until it declares explicit support for Python 3.11
        run: |
          python -m pip install --upgrade pip
          pip install vyper==0.3.7 --ignore-requires-python
          pip install -r requirements_dev.txt


================================================
FILE: .github/workflows/libcheck.yml
================================================
##
## Copyright 2023 Ocean Protocol Foundation
## SPDX-License-Identifier: Apache-2.0
##
name: Ocean.py library check

on:
  schedule:
    - cron: '30 5 * * 2'
  workflow_dispatch:

jobs:
  build:
    environment: CC_REPORTER_ID
    runs-on: ubuntu-latest
    steps:
      - name: Setup Ocean.py
        uses: actions/checkout@v2
      - name: Set up Python 3.8
        uses: actions/setup-python@v2
        with:
          python-version: '3.8'
      - uses: actions/checkout@v2
        name: Checkout Barge
        with:
          repository: "oceanprotocol/barge"
          path: 'barge'
      - name: Run Barge
        working-directory: ${{ github.workspace }}/barge
        env:
          GANACHE_FORK: london
        run: |
          bash -x start_ocean.sh --no-dashboard 2>&1 --with-provider2 --with-c2d > start_ocean.log &
          for i in $(seq 1 108); do
            sleep 5
            [ -f "$HOME/.ocean/ocean-contracts/artifacts/ready" -a -f "$HOME/.ocean/ocean-c2d/ready" ] && break
            done
          ls -la "$HOME/.ocean/ocean-contracts/artifacts/"
      - name: Install dependencies
        working-directory: ${{ github.workspace }}
        run: |
          python -m pip install --upgrade pip
          pip install ocean-lib
          pip install mkcodes pytest matplotlib
      - name: Delete default runner images
        run: |
          docker image rm node:14
          docker image rm node:14-alpine
          docker image rm node:16
          docker image rm node:16-alpine
          docker image rm node:18
          docker image rm node:18-alpine
          docker image rm buildpack-deps:buster
          docker image rm buildpack-deps:bullseye
          docker image rm debian:10
          docker image rm debian:11
          docker image rm moby/buildkit:latest
      - name: Generate and test readmes
        working-directory: ${{ github.workspace }}
        env:
          TEST_PRIVATE_KEY1: "0x8467415bb2ba7c91084d932276214b11a3dd9bdb2930fefa194b666dd8020b99"
          TEST_PRIVATE_KEY2: "0x1d751ded5a32226054cd2e71261039b65afb9ee1c746d055dd699b1150a5befc"
          TEST_PRIVATE_KEY3: "0x732fbb7c355aa8898f4cff92fa7a6a947339eaf026a08a51f171199e35a18ae0"
          ADDRESS_FILE: "~/.ocean/ocean-contracts/artifacts/address.json"
          OCEAN_NETWORK_URL: "http://127.0.0.1:8545"
          OCEAN_CONFIG_FILE: "config.ini"
          FACTORY_DEPLOYER_PRIVATE_KEY: "0xc594c6e5def4bab63ac29eed19a134c130388f74f019bc74b8f4389df2837a58"
          MUMBAI_RPC_URL: ${{ secrets.MUMBAI_RPC_URL }}
        run: |
          mkcodes --github --output tests/generated-readmes/test_{name}.{ext} READMEs
          pytest tests/readmes/test_readmes.py
      - name: Slack notify via webhook
        uses: up9cloud/action-notify@master
        if: cancelled() == false
        env:
          GITHUB_JOB_STATUS: ${{ job.status }}
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}


================================================
FILE: .github/workflows/pytest.yml
================================================
##
## Copyright 2023 Ocean Protocol Foundation
## SPDX-License-Identifier: Apache-2.0
##
name: Ocean.py tests

on:
  - push
  - pull_request

env:
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

jobs:
  build:
    environment: CC_REPORTER_ID
    runs-on: ubuntu-latest
    steps:
      - name: Setup Ocean.py
        uses: actions/checkout@v2
      - name: Set up Python 3.8
        uses: actions/setup-python@v2
        with:
          python-version: '3.8'
      - uses: actions/checkout@v2
        name: Checkout Barge
        with:
          repository: "oceanprotocol/barge"
          path: 'barge'
      - name: Run Barge
        working-directory: ${{ github.workspace }}/barge
        env:
          GANACHE_FORK: london
        run: |
          bash -x start_ocean.sh --no-dashboard 2>&1 --with-provider2 --with-thegraph --with-c2d --skip-subgraph-deploy > start_ocean.log &
      - name: Install dependencies
        working-directory: ${{ github.workspace }}
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements_dev.txt
      - name: Delete default runner images
        run: |
          docker image rm node:16
          docker image rm node:16-alpine
          docker image rm node:18
          docker image rm node:18-alpine
          docker image rm debian:10
          docker image rm debian:11
          docker image rm moby/buildkit:latest
      - name: Wait for contracts deployment
        working-directory: ${{ github.workspace }}/barge
        run: |
          for i in $(seq 1 250); do
            sleep 5
            [ -f "$HOME/.ocean/ocean-contracts/artifacts/ready" -a -f "$HOME/.ocean/ocean-c2d/ready" ] && break
            done
      - name: "Read address.json contents"
        working-directory: ${{ github.workspace }}
        run: cat "$HOME/.ocean/ocean-contracts/artifacts/address.json"
      - name: Test with pytest
        run: |
          mkcodes --github --output tests/generated-readmes/test_{name}.{ext} READMEs
          coverage run --source ocean_lib -m pytest
          coverage report
          coverage xml
        env:
          REMOTE_TEST_PRIVATE_KEY1: ${{secrets.REMOTE_TEST_PRIVATE_KEY1}}
          REMOTE_TEST_PRIVATE_KEY2: ${{secrets.REMOTE_TEST_PRIVATE_KEY2}}
          MUMBAI_RPC_URL: ${{secrets.MUMBAI_RPC_URL}}
      - name:  docker logs
        run: docker logs ocean_aquarius_1 && docker logs ocean_provider_1
        if: ${{ failure() }}
      - name: Publish code coverage
        uses: paambaati/codeclimate-action@v2.7.5
        env:
          CC_TEST_REPORTER_ID: ${{secrets.CC_TEST_REPORTER_ID}}


================================================
FILE: .github/workflows/release.yml
================================================
##
## Copyright 2023 Ocean Protocol Foundation
## SPDX-License-Identifier: Apache-2.0
##
name: Ocean.py release

on:
  release:
    types: [created]

jobs:
  build-n-publish:
    runs-on: ubuntu-latest
    steps:
      - name: Setup Ocean.py
        uses: actions/checkout@v2
      - name: Set up Python 3.8
        uses: actions/setup-python@v2
        with:
          python-version: '3.8'
      - name: Install pypa/build
        run: >-
          python -m
          pip install
          build
          --user
      - name: Build a binary wheel and a source tarball
        run: >-
          python -m
          build
          --sdist
          --wheel
          --outdir dist/
      - name: Publish package
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          user: __token__
          verbose: true
          password: ${{ secrets.PYPI_PASSWORD }}



================================================
FILE: .gitignore
================================================
.history
__pycache__
.pytest_cache/
*.pyc
*~
.eggs/
artifacts/address.json
/venv/
ocean_lib.egg-info/
/build/
/contracts/
/interfaces/
/reports/
/tests/generated-readmes/test*

.coverage
.tox/
consume-downloads/
coverage.xml
setup-local.sh


================================================
FILE: .pre-commit-config.yaml
================================================
##
## Copyright 2023 Ocean Protocol Foundation
## SPDX-License-Identifier: Apache-2.0
##
repos:
-   repo: https://github.com/PyCQA/isort
    rev: 5.12.0
    hooks:
    - id: isort
-   repo: https://github.com/psf/black
    rev: 'refs/tags/22.6.0:refs/tags/22.6.0'
    hooks:
    -   id: black
-   repo: https://github.com/pycqa/flake8
    rev: 6.0.0
    hooks:
    - id: flake8
-   repo: https://github.com/johann-petrak/licenseheaders.git
    rev: v0.8.8
    hooks:
    - id: licenseheaders
      args: ["-t", ".copyright.tmpl", "-f"]


================================================
FILE: .prospector.yml
================================================
##
## Copyright 2023 Ocean Protocol Foundation
## SPDX-License-Identifier: Apache-2.0
##
pep257:
  disable:
    - D213

pylint:
  run: false

frosted:
  run: false

mypy:
  run: false

pyroma:
  run: false


================================================
FILE: CHANGELOG.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->
See [`releases`](https://github.com/oceanprotocol/ocean.py/releases).


================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
<!--
Copyright 2025 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

> ocean.py: a Python library to privately & securely publish, exchange, and consume data.

⚠ Note: as of early 2025, this codebase is not being maintained. It might work, it might not. If you find a bug, feel free to report it, but do not expect it to be fixed. 

Ocean.py helps data scientists earn $ from their AI models, track provenance of data & compute, and get more data. (More details [here](https://docs.oceanprotocol.com/data-science).)

Ocean.py makes these tasks easy:

- **Publish** data services: data feeds, REST APIs, downloadable files or compute-to-data. Create an ERC721 **data NFT** for each service, and ERC20 **datatoken** for access (1.0 datatokens to access).
- **Sell** datatokens via for a fixed price. Sell data NFTs.
- **Transfer** data NFTs & datatokens to another owner, and **all other ERC721 & ERC20 actions** using [web3.py](https://web3py.readthedocs.io).

ocean.py is part of the [Ocean Protocol](https://www.oceanprotocol.com) toolset.

This is in beta state. If you run into problems, please open up a [new issue](/issues).

## 🏄 Quickstart

Follow these steps in sequence to ramp into Ocean.

 1. **[Install Ocean](READMEs/install.md)**
 2. **Setup:**
    - **[Remote](READMEs/setup-remote.md)** (Win, MacOS, Linux)
    - *or* **[Local](READMEs/setup-local.md)** (Linux only)
 3. **[Walk through main flow](READMEs/main-flow.md)**: publish asset, post for free / for sale, dispense it / buy it, and consume it

### Tools

- [Define gas strategy](READMEs/gas-strategy-remote.md) - auto-determine gas fee for remote networks
- [Search & filter data](READMEs/search-and-filter-assets.md) - find assets by tag
- [Custody-light flow](READMEs/custody-light-flow.md) - consume a free & a priced asset without custody

### Use-case flows

- [Challenge DF](https://github.com/oceanprotocol/predict-eth) - prize $$ to predict future ETH price
- [Data Farming](READMEs/df.md) - curate data assets, earn rewards

### On-chain key-value store via data NFTs

- [Sharing public data on-chain](READMEs/key-value-public.md) - e.g. public AI models
- [Sharing private data on-chain](READMEs/key-value-private.md) - e.g. private AI models

### More types of data assets

Each of the following shows how to publish & consume a particular type of data.
- [C2D](READMEs/c2d-flow.md) - tokenize & monetize AI algorithms via Compute-to-Data
- [REST API](READMEs/publish-flow-restapi.md) - Example on Binance ETH price feed
- [GraphQL](READMEs/publish-flow-graphql.md) - Example on Ocean Data NFTs
- [On-chain data](READMEs/publish-flow-onchain.md) - Example on Ocean swap fees
- [Adding credentials](READMEs/publish-flow-credentials.md) - Example on publishing an asset with custom credentials

### Learn more
- [Understand config parameters](READMEs/parameters.md) - envvars vs files
- [Learn about off-chain services](READMEs/services.md) - Ocean Provider for data services, Aquarius metadata store

## 🦑 Development

- **[Developers flow](READMEs/developers.md)** - to further develop ocean.py
- [Release process](READMEs/release-process.md) - to do a new release of ocean.py

## 🏛 License

    Copyright ((C)) 2025 Ocean Protocol Foundation

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.



================================================
FILE: READMEs/c2d-flow-more-examples.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

# Compute-to-Data (C2D) Flow - More Examples

Please note that these code snippets are not automatically tested, so they might be out of date. Always refer to the main
[c2d-flow README](https://github.com/oceanprotocol/ocean.py/blob/v4main/READMEs/c2d-flow.md) for the latest fully tested c2d flow.

## Example 1: Image Processing

Run the [c2d-flow README](https://github.com/oceanprotocol/ocean.py/blob/v4main/READMEs/c2d-flow.md)
with the following alterations:

### 3. Alice publishes a dataset

In Step #3 where Alice publishes a dataset, use [peppers.tiff](https://sipi.usc.edu/database/database.php?volume=misc&image=13#top):

```python
# Specify metadata, using the peppers.tiff image
DATA_date_created = "2021-12-28T10:55:11Z"
DATA_metadata = {
    "created": DATA_date_created,
    "updated": DATA_date_created,
    "description": "peppers image",
    "name": "peppers",
    "type": "dataset",
    "author": "Trent",
    "license": "CC0: PublicDomain",
}

# ocean.py offers multiple file types, but a simple url file should be enough for this example
from ocean_lib.structures.file_objects import UrlFile
DATA_url_file = UrlFile(
    url="https://raw.githubusercontent.com/oceanprotocol/c2d-examples/main/peppers_and_grayscale/peppers.tiff"
)
```

### 4. Alice publishes an algorithm

In step #4 where Alice publishes an algorithm, use a standard grayscale algorithm:

```python
# Specify metadata, using the grayscale algorithm
ALGO_date_created = "2021-12-28T10:55:11Z"
ALGO_metadata = {
    "created": ALGO_date_created,
    "updated": ALGO_date_created,
    "description": "grayscale",
    "name": "grayscale",
    "type": "algorithm",
    "author": "Trent",
    "license": "CC0: PublicDomain",
    "algorithm": {
        "language": "python",
        "format": "docker-image",
        "version": "0.1",
        "container": {
            "entrypoint": "python $ALGO",
            "image": "oceanprotocol/algo_dockers",
            "tag": "python-branin",  # This image provides all the dependencies of the grayscale.py algorithm
            "checksum": "sha256:8221d20c1c16491d7d56b9657ea09082c0ee4a8ab1a6621fa720da58b09580e4",
        },
    }
}

# ocean.py offers multiple file types, but a simple url file should be enough for this example
from ocean_lib.structures.file_objects import UrlFile
ALGO_url_file = UrlFile(
    url="https://raw.githubusercontent.com/oceanprotocol/c2d-examples/main/peppers_and_grayscale/grayscale.py"
)
```

### Display and Save the Result

Install dependencies:

`pip install Pillow`

Display the image:

```python
from PIL import Image
import io

image = Image.open(io.BytesIO(result))
image.show()
```

Save the image:

```python
image.save('grayscale.png')
```

## Example 2: Logistic Regression for Classification

Run the [c2d-flow README](https://github.com/oceanprotocol/ocean.py/blob/v4main/READMEs/c2d-flow.md)
with the following alterations:

### 3. Alice publishes a dataset

In Step #3 where Alice publishes a dataset, use the [Iris Flower Dataset](https://en.wikipedia.org/wiki/Iris_flower_data_set):

```python
# Specify metadata, using the iris dataset
DATA_date_created = "2019-12-28T10:55:11Z"
DATA_metadata = {
    "created": DATA_date_created,
    "updated": DATA_date_created,
    "description": "The Iris flower dataset is a multivariate dataset to train classification algorithms",
    "name": "Iris Flower Dataset",
    "type": "dataset",
    "author": "Ocean Protocol & Raven Protocol",
    "license": "MIT",
}

# ocean.py offers multiple file types, but a simple url file should be enough for this example
from ocean_lib.structures.file_objects import UrlFile
DATA_url_file = UrlFile(
    url="https://raw.githubusercontent.com/oceanprotocol/c2d-examples/main/iris_and_logisitc_regression/dataset_61_iris.csv"
)
```

### 4. Alice publishes an algorithm

In step #4 where Alice publishes an algorithm, use a standard grayscale algorithm:

```python
# Specify metadata, using the Logistic Regression algorithm
ALGO_date_created = "2020-01-28T10:55:11Z"
ALGO_metadata = {
    "created": ALGO_date_created,
    "updated": ALGO_date_created,
    "description": "Logistic Regression",
    "name": "Logistic Regression",
    "type": "algorithm",
    "author": "Ocean Protocol & Raven Protocol",
    "license": "MIT",
    "algorithm": {
        "language": "python",
        "format": "docker-image",
        "version": "0.1",
        "container": {
            "entrypoint": "python $ALGO",
            "image": "oceanprotocol/algo_dockers",
            "tag": "python-panda", # This image provides all the dependencies of the logistic_regression.py algorithm
            "checksum": "sha256:7fc268f502935d11ff50c54e3776dda76477648d5d83c2e3c4fdab744390ecf2",
        },
    }
}

# ocean.py offers multiple file types, but a simple url file should be enough for this example
from ocean_lib.structures.file_objects import UrlFile
ALGO_url_file = UrlFile(
    url="https://raw.githubusercontent.com/oceanprotocol/c2d-examples/main/iris_and_logisitc_regression/logistic_regression.py"
)
```

### Display the Result

Install dependencies:

`pip install numpy, matplotlib`

Display the result:

```python
import numpy as np
import matplotlib.pyplot as plt

h = 0.02  # step size in the mesh
xx, yy = np.meshgrid(np.arange(3.8, 8.4, h), np.arange(1.5, 4.9, h))

plt.figure(1, figsize=(4, 3))
plt.pcolormesh(xx, yy, model, cmap=plt.cm.Paired)

plt.xlabel("Sepal length")
plt.ylabel("Sepal width")

plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())

plt.show()
```


================================================
FILE: READMEs/c2d-flow.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

# Quickstart: Compute-to-Data (C2D) Flow

This quickstart describes a C2D flow, using a remote setup on Mumbai testnet.

Here are the steps:

1. Setup
2. Alice publishes dataset
3. Alice publishes algorithm
4. Alice allows the algorithm for C2D for that data asset
5. Bob acquires datatokens for data and algorithm
6. Bob starts a compute job using a free C2D environment (no provider fees)
7. Bob monitors logs / algorithm output

Let's go through each step.

## 1. Setup

### 1.1 Install Ocean

First, ensure that you've [installed Ocean](install.md)

### 1.2 Install matplotlib

This example uses C2D to create a regression model. We'll use the library `matplotlib` to visualize it.

In the same console:
```console
#ensure you're in the Python virtualenv
source venv/bin/activate

#install matplotlib
pip install matplotlib
```

### 1.3 Setup remotely

Follow [setup-remote.md](setup-remote.md).

## 2. Alice publishes dataset

In the same python console:

```python

# Publish data NFT, datatoken, and asset for dataset based on url

# ocean.py offers multiple file object types. A simple url file is enough for here
from ocean_lib.structures.file_objects import UrlFile
DATA_url_file = UrlFile(
    url="https://raw.githubusercontent.com/oceanprotocol/c2d-examples/main/branin_and_gpr/branin.arff"
)

name = "Branin dataset"
(DATA_data_nft, DATA_datatoken, DATA_ddo) = ocean.assets.create_url_asset(name, DATA_url_file.url, {"from": alice}, with_compute=True, wait_for_aqua=True)
print(f"DATA_data_nft address = '{DATA_data_nft.address}'")
print(f"DATA_datatoken address = '{DATA_datatoken.address}'")

print(f"DATA_ddo did = '{DATA_ddo.did}'")
```

To customise the privacy and accessibility of your compute service, add the `compute_values` argument to
`create_url_asset` to set values according to the [DDO specs](https://docs.oceanprotocol.com/core-concepts/did-ddo).
The function assumes the documented defaults.

## 3. Alice publishes an algorithm

In the same Python console:

```python
# Publish data NFT & datatoken for algorithm
ALGO_url = "https://raw.githubusercontent.com/oceanprotocol/c2d-examples/main/branin_and_gpr/gpr.py"

name = "grp"
(ALGO_data_nft, ALGO_datatoken, ALGO_ddo) = ocean.assets.create_algo_asset(name, ALGO_url, {"from": alice}, wait_for_aqua=True)

print(f"ALGO_data_nft address = '{ALGO_data_nft.address}'")
print(f"ALGO_datatoken address = '{ALGO_datatoken.address}'")
print(f"ALGO_ddo did = '{ALGO_ddo.did}'")
```

## 4. Alice allows the algorithm for C2D for that data asset

In the same Python console:
```python
compute_service = DATA_ddo.services[1]
compute_service.add_publisher_trusted_algorithm(ALGO_ddo)
DATA_ddo = ocean.assets.update(DATA_ddo, {"from": alice})

```

## 5. Bob acquires datatokens for data and algorithm

In the same Python console:
```python
# Alice mints DATA datatokens and ALGO datatokens to Bob.
# Alternatively, Bob might have bought these in a market.
from ocean_lib.ocean.util import to_wei
DATA_datatoken.mint(bob, to_wei(5), {"from": alice})
ALGO_datatoken.mint(bob, to_wei(5), {"from": alice})
```

## 6. Bob starts a compute job using a free C2D environment

Only inputs needed: DATA_did, ALGO_did. Everything else can get computed as needed.
For demo purposes, we will use the free C2D environment, which requires no provider fees.

In the same Python console:
```python
# Convenience variables
DATA_did = DATA_ddo.did
ALGO_did = ALGO_ddo.did

# Operate on updated and indexed assets
DATA_ddo = ocean.assets.resolve(DATA_did)
ALGO_ddo = ocean.assets.resolve(ALGO_did)

compute_service = DATA_ddo.services[1]
algo_service = ALGO_ddo.services[0]
free_c2d_env = ocean.compute.get_free_c2d_environment(compute_service.service_endpoint, DATA_ddo.chain_id)

from datetime import datetime, timedelta, timezone
from ocean_lib.models.compute_input import ComputeInput

DATA_compute_input = ComputeInput(DATA_ddo, compute_service)
ALGO_compute_input = ComputeInput(ALGO_ddo, algo_service)

# Pay for dataset and algo for 1 day
datasets, algorithm = ocean.assets.pay_for_compute_service(
    datasets=[DATA_compute_input],
    algorithm_data=ALGO_compute_input,
    consume_market_order_fee_address=bob.address,
    tx_dict={"from": bob},
    compute_environment=free_c2d_env["id"],
    valid_until=int((datetime.now(timezone.utc) + timedelta(days=1)).timestamp()),
    consumer_address=free_c2d_env["consumerAddress"],
)
assert datasets, "pay for dataset unsuccessful"
assert algorithm, "pay for algorithm unsuccessful"

# Start compute job
job_id = ocean.compute.start(
    consumer_wallet=bob,
    dataset=datasets[0],
    compute_environment=free_c2d_env["id"],
    algorithm=algorithm,
)
print(f"Started compute job with id: {job_id}")
```

## 7. Bob monitors logs / algorithm output

In the same Python console, you can check the job status as many times as needed:

```python
# Wait until job is done
import time
from decimal import Decimal
succeeded = False
for _ in range(0, 200):
    status = ocean.compute.status(DATA_ddo, compute_service, job_id, bob)
    if status.get("dateFinished") and Decimal(status["dateFinished"]) > 0:
        succeeded = True
        break
    time.sleep(5)
```

This will output the status of the current job.
Here is a list of possible results: [Operator Service Status description](https://github.com/oceanprotocol/operator-service/blob/main/API.md#status-description).

Once the returned status dictionary contains the `dateFinished` key, Bob can retrieve the job results using ocean.compute.result or, more specifically, just the output if the job was successful.
For the purpose of this tutorial, let's choose the second option.

```python
# Retrieve algorithm output and log files
output = ocean.compute.compute_job_result_logs(
    DATA_ddo, compute_service, job_id, bob
)[0]

import pickle
model = pickle.loads(output)  # the gaussian model result
assert len(model) > 0, "unpickle result unsuccessful"
```

You can use the result however you like. For the purpose of this example, let's plot it.

```python
import numpy
from matplotlib import pyplot

X0_vec = numpy.linspace(-5., 10., 15)
X1_vec = numpy.linspace(0., 15., 15)
X0, X1 = numpy.meshgrid(X0_vec, X1_vec)
b, c, t = 0.12918450914398066, 1.5915494309189535, 0.039788735772973836
u = X1 - b * X0 ** 2 + c * X0 - 6
r = 10. * (1. - t) * numpy.cos(X0) + 10
Z = u ** 2 + r

fig, ax = pyplot.subplots(subplot_kw={"projection": "3d"})
ax.scatter(X0, X1, model, c="r", label="model")
pyplot.title("Data + model")
pyplot.show()  # or pyplot.savefig("test.png") to save the plot as a .png file instead
```

You should see something like this:

![test](https://user-images.githubusercontent.com/4101015/134895548-82e8ede8-d0db-433a-b37e-694de390bca3.png)

## Appendix. Tips & tricks

This README has a simple ML algorithm. However, Ocean C2D is not limited to usage in ML. The file [c2d-flow-more-examples.md](https://github.com/oceanprotocol/ocean.py/blob/v4main/READMEs/c2d-flow-more-examples.md) has examples from vision and other fields.

In the "publish algorithm" step, to replace the sample algorithm with another one:

- Use one of the standard [Ocean algo_dockers images](https://github.com/oceanprotocol/algo_dockers) or publish a custom docker image.
- Use the image name and tag in the `container` part of the algorithm metadata.
- The image must have basic support for installing dependencies. E.g. "pip" for the case of Python. You can use other languages, of course.
- More info: https://docs.oceanprotocol.com/tutorials/compute-to-data-algorithms/)

The function to `pay_for_compute_service` automates order starting, order reusing and performs all the necessary Provider and on-chain requests.
It modifies the contents of the given ComputeInput as follows:

- If the dataset/algorithm contains a `transfer_tx_id` property, it will try to reuse that previous transfer id. If provider fees have expired but the order is still valid, then the order is reused on-chain.
- If the dataset/algorithm does not contain a `transfer_tx_id` or the order has expired (based on the Provider's response), then one new order will be created.

This means you can reuse the same ComputeInput and you don't need to regenerate it everytime it is sent to `pay_for_compute_service`. This step makes sure you are not paying unnecessary or duplicated fees.

If you wish to upgrade the compute resources, you can use any (paid) C2D environment.
Inspect the results of `ocean.ocean_compute.get_c2d_environments(service.service_endpoint, DATA_ddo.chain_id)` and `ocean.retrieve_provider_fees_for_compute(datasets, algorithm_data, consumer_address, compute_environment, duration)` for a preview of what you will pay.
Don't forget to handle any minting, allowance or approvals on the desired token to ensure transactions pass.


================================================
FILE: READMEs/custody-light-flow.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

# Custody-light flow

It allows orgs to buy & consume data without having custody of assets.

We assume you've already (a) [installed Ocean](install.md), and (b) done [local setup](setup-local.md) or [remote setup](setup-remote.md). This flow works for either one, without any changes between them (!)

This flow is split in two sections:
- free steps: publish free asset with a Datatoken 2 (enterprise template), then consume;
- priced steps: publish a priced asset attached to a Datatoken 2 (enterprise template), then buy / consume.

Let's go!


## Free steps

Steps in this flow:

1. Alice publishes a free asset
2. Bob dispenses funds from the asset's pricing schema
3. Bob consumes the asset

### 1. Alice publishes a free asset

In the same Python console:
```python
#data info
name = "Branin dataset"
url = "https://raw.githubusercontent.com/trentmc/branin/main/branin.arff"

#create data asset
from ocean_lib.models.dispenser import DispenserArguments
from ocean_lib.ocean.util import to_wei

(data_nft, datatoken, ddo) = ocean.assets.create_url_asset(name, url, {"from": alice}, dt_template_index=2, pricing_schema_args=DispenserArguments(to_wei(1), to_wei(1)))

#print
print("Just published a free asset:")
print(f"  data_nft: symbol={data_nft.symbol}, address={data_nft.address}")
print(f"  datatoken: symbol={datatoken.symbol}, address={datatoken.address}")
print(f"  did={ddo.did}")
```

### 2. Bob dispenses funds from the asset's pricing schema

Bob wants to consume Alice's asset. He can dispense 1.0 datatokens to complete his job.
Below, we show the possible approach:

```python

provider_fees = ocean.retrieve_provider_fees(
    ddo, ddo.services[0], publisher_wallet=bob
)

tx = datatoken.dispense_and_order(provider_fees, {"from": bob}, consumer=bob.address, service_index=0)

```

### 3. Bob consumes the asset

Bob now has the transaction receipt to prove that he dispensed funds! Time to download the dataset and use it.


In the same Python console:
```python
# Bob downloads the file. If the connection breaks, Bob can try again
asset_dir = ocean.assets.download_asset(ddo, bob, './', tx.transactionHash.hex())

import os
file_name = os.path.join(asset_dir, "file0")
```

Let's check that the file is downloaded. In a new console:

```console
cd my_project/datafile.did:op:0xAf07...
ls branin.arff
```


## Priced steps

Steps in this flow:

1. Alice publishes a priced asset
2. Bob buys funds from the asset's pricing schema
3. Bob consumes the asset

### 1. Alice publishes a free asset

In the same Python console:
```python
# data info
name = "Branin dataset"
url = "https://raw.githubusercontent.com/trentmc/branin/main/branin.arff"

# create data asset
from ocean_lib.models.fixed_rate_exchange import ExchangeArguments
from ocean_lib.ocean.util import to_wei

(data_nft, datatoken, ddo) = ocean.assets.create_url_asset(name, url, {"from": alice}, dt_template_index=2, pricing_schema_args=ExchangeArguments(
            rate=to_wei(3), base_token_addr=ocean.OCEAN_address, dt_decimals=18
        ),)

#print
print("Just published a priced asset:")
print(f"  data_nft: symbol={data_nft.symbol}, address={data_nft.address}")
print(f"  datatoken: symbol={datatoken.symbol}, address={datatoken.address}")
print(f"  did={ddo.did}")
```

### 2. Bob buys funds from the asset's pricing schema

Bob wants to consume Alice's asset. He can buy 1.0 datatokens to complete his job.
Below, we show the possible approach:

```python

provider_fees = ocean.retrieve_provider_fees(
    ddo, ddo.services[0], publisher_wallet=bob
)
exchange = datatoken.get_exchanges()[0]
OCEAN = ocean.OCEAN_token
OCEAN.approve(
        datatoken.address,
        to_wei(10),
        {"from": bob},
)
OCEAN.approve(
    exchange.address,
    to_wei(10),
    {"from": bob},
)
tx = datatoken.buy_DT_and_order(provider_fees, exchange, {"from": bob}, consumer=bob.address, service_index=0)

```

### 3. Bob consumes the asset

Bob now has the transaction receipt to prove that he bought funds from the exchange! Time to download the dataset and use it.


In the same Python console:
```python
# Bob downloads the file. If the connection breaks, Bob can try again
asset_dir = ocean.assets.download_asset(ddo, bob, './', tx.transactionHash.hex())

import os
file_name = os.path.join(asset_dir, "file0")
```

Let's check that the file is downloaded. In a new console:

```console
cd my_project/datafile.did:op:0xAf07...
ls branin.arff
```


================================================
FILE: READMEs/developers.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

# Developing ocean.py

This README is how to further _develop_ ocean.py. (Compare to the quickstarts which show how to _use_ it.)
Steps:

1.  **Install dependencies**
2.  **Run barge services**
3.  **Set up contracts**
4.  **Test**
5.  **Merge** the changes via a PR
6.  **Release**

## 1. Install dependencies

### Prerequisites

-   Linux/MacOS
-   Docker, [allowing non-root users](https://www.thegeekdiary.com/run-docker-as-a-non-root-user/)
-   Python 3.8.5+

### Do Install

In a new console that we'll call the _work_ console (as we'll use it later):

```console
# Clone the repo and enter into it
git clone https://github.com/oceanprotocol/ocean.py
cd ocean.py

# Install OS dependencies
sudo apt-get install -y python3-dev gcc

# Initialize virtual environment and activate it.
# Make sure your Python version inside the venv is >=3.8.
python3 -m venv venv
source venv/bin/activate

# Install modules in the environment.
pip install -r requirements_dev.txt
```

## 2. Run barge services

In a new console:

```console
# grab repo
git clone https://github.com/oceanprotocol/barge
cd barge

# clean up old containers (to be sure)
docker system prune -a --volumes

# for support of type 2 transactions
export GANACHE_FORK=london

# Run barge: start Ganache, Provider, Aquarius; deploy contracts; update ~/.ocean
# The `--with-c2d` option tells barge to include the Compute-to-Data backend
./start_ocean.sh --with-c2d
```

(Or, [run services separately](services.md).)

## 3. Set up contracts

In work console:

```console
# set private keys of two local (ganache) accounts
export TEST_PRIVATE_KEY1=0x8467415bb2ba7c91084d932276214b11a3dd9bdb2930fefa194b666dd8020b99
export TEST_PRIVATE_KEY2=0x1d751ded5a32226054cd2e71261039b65afb9ee1c746d055dd699b1150a5befc

# needed to mint fake OCEAN for testing with ganache
export FACTORY_DEPLOYER_PRIVATE_KEY=0xc594c6e5def4bab63ac29eed19a134c130388f74f019bc74b8f4389df2837a58
```

Some tests run on Mumbai (e.g. test_mumbai.py), which need fake MATIC. So you also need:
```console
# set private keys of two remote accounts
export REMOTE_TEST_PRIVATE_KEY1=<your remote private key 1>
export REMOTE_TEST_PRIVATE_KEY2=<your remote private key 2>
```

These keys aren't public because bots could eat the fake MATIC. You need to generate your own, and fill them with a faucet; see instructions in remote setup README. Or, [access-protected OPF keys](https://github.com/oceanprotocol/private-keys/blob/main/README.md)).

## 4. Test

In work console:
```console
# run a single test
pytest ocean_lib/models/test/test_data_nft_factory.py::test_start_multiple_order

# run all tests in a file
pytest ocean_lib/models/test/test_data_nft_factory.py

# run all regular tests; see details on pytest markers to select specific suites
pytest
```

The README tests are special. Here's how to run them:
```console
# need to auto-generate READMEs first
mkcodes --github --output tests/generated-readmes/test_{name}.{ext} READMEs

# then run the tests
pytest tests/readmes/test_readmes.py
pytest /tests/integration/remote/test_mumbai_readme.py
```

For envvars that aren't set, `pytest` uses values in `pytest.ini`.


## 5. Merge

Merge the changes via a pull request (PR) etc.

Specifically, [follow this workflow](https://docs.oceanprotocol.com/concepts/contributing/#fix-or-improve-core-software).

## 6. Release

Release for pip etc.

Specifically, [follow the Release Process instructions](./release-process.md).

## 7. Appendix: More tests

### 7.1 Pre-commit hooks

In main console (with venv on):

```console
pre-commit install
```

Now, this will auto-apply isort (import sorting), flake8 (linting) and black (automatic code formatting) to commits. Black formatting is the standard and is checked as part of pull requests.

## 8. Appendix: Contributing to docs

You are welcome to contribute to ocean.py docs and READMEs. For clean markdowns in the READMEs folder, we use the `remark` tool for automatic markdown formatting.
OCEAN has an official repository containing remark settings, so please follow the instructions [here](https://github.com/oceanprotocol/ocean-remark).


================================================
FILE: READMEs/df.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->
# Quickstart: Data Farming Flow

This README shows how to do steps in Ocean Data Farming (DF), where you curate data assets to earn rewards. It also helps to democratize "wash consume" until it becomes unprofitable.

Here are the steps:

1. Setup, in Ganache
2. Lock OCEAN for veOCEAN
3. Publish dataset & exchange
4. Allocate veOCEAN to dataset
5. Fake-consume data
6. Collect OCEAN rewards
7. Repeat steps 1-6, for Eth mainnet

Let's go through each step.

## 1. Setup

Ensure that you've already (a) [installed Ocean](install.md), and (b) [set up locally](setup-local.md).


## 2. Lock OCEAN for veOCEAN

First, let's set some key parameters for veOCEAN and DF. On Ganache, you can use these values as-is. But on Eth mainnet, you must choose your own. In the same Python console:
```python
# On your asset, your DCV = DT_price * num_consumes
# Your asset gets rewards pro-rata for its DCV compared to other assets' DCVs.
DT_price = 100.0 # number of OCEAN needed to buy one datatoken
num_consumes = 3

# This is how much OCEAN to lock into veOCEAN. It can be small if you're
# the only staker on your asset. If others stake on your asset, your
# rewards are pro-rate compared to others' stake in your asset.
amt_OCEAN_lock = 10.0
```

Now, let's lock OCEAN for veOCEAN. In the same Python console:
```python
# simulate passage of time, until next Thursday, the start of DF(X)
web3 = ocean.config_dict["web3_instance"]
provider = web3.provider
latest_block = web3.eth.get_block("latest")

WEEK = 7 * 86400 # seconds in a week
t0 = latest_block.timestamp
t1 = t0 // WEEK * WEEK + WEEK # this is a Thursday, because Jan 1 1970 was
t2 = t1 + WEEK
provider.make_request("evm_increaseTime", [(t1 - t0)])

#we're now at the beginning of the week. So, lock
veOCEAN = ocean.veOCEAN
OCEAN.approve(veOCEAN.address, to_wei(amt_OCEAN_lock), {"from" : alice})

import math
web3 = ocean.config_dict["web3_instance"]
latest_block = web3.eth.get_block("latest")
veOCEAN.withdraw({
    "from": alice,
    "gas": latest_block.gasLimit,
    "gasPrice": math.ceil(latest_block["baseFeePerGas"] * 1.2),
}) # withdraw old tokens first

latest_block = web3.eth.get_block("latest")
veOCEAN.create_lock(
    to_wei(amt_OCEAN_lock),
    t2,
    {
        "from": alice,
        "gas": latest_block.gasLimit,
        "gasPrice": math.ceil(latest_block["baseFeePerGas"] * 1.2),
    })
```


## 3. Publish Dataset & Exchange

In the same Python console:
```python
#data info
name = "Branin dataset"
url = "https://raw.githubusercontent.com/trentmc/branin/main/branin.arff"

#create data asset
(data_NFT, DT, ddo) = ocean.assets.create_url_asset(name, url, {"from": alice}, wait_for_aqua=False)
print(f"Just published asset, with data_NFT.address={data_NFT.address}")

#create exchange
exchange = DT.create_exchange({"from": alice}, to_wei(DT_price), OCEAN.address)

#make datatokens available on the exchange
DT.mint(alice, to_wei(num_consumes), {"from": alice})
DT.approve(exchange.address, to_wei(num_consumes), {"from": alice})
```


## 4. Stake on dataset

To stake, you allocate veOCEAN to dataset. In the same Python console:
```python
amt_allocate = 100 #total allocation must be <= 10000 (wei)
ocean.ve_allocate.setAllocation(amt_allocate, data_NFT.address, web3.eth.chain_id, {"from": alice})
```

## 5. Fake-consume data

"Wash consuming" is when the publisher fake-consumes data to drive data consume volume (DCV) to get more rewards. Not healthy for the ecosystem long-term. Good news: if consume fee > weekly rewards, then wash consume becomes unprofitable. DF is set up to make this happen by DF29 (if not sooner). [Details](https://twitter.com/trentmc0/status/1587527525529358336).

In the meantime, this README helps level the playing field around wash consume. This step shows how to do fake-consume.

```python
# Alice buys datatokens from herself
OCEAN_pay = DT_price * num_consumes
OCEAN_alice = from_wei(OCEAN.balanceOf(alice))
assert OCEAN_alice >= OCEAN_pay, f"Have just {OCEAN_alice} OCEAN"

OCEAN.approve(exchange.address, to_wei(OCEAN_alice), {"from": alice})
exchange.buy_DT(to_wei(num_consumes), {"from": alice})

DT_bal = from_wei(DT.balanceOf(alice))
assert DT_bal >= num_consumes, \
    f"Have {DT_bal} datatokens, too few for {num_consumes} consumes"

# Alice sends datatokens to the service, to get access. This is the "consume".
for i in range(num_consumes):
    print(f"Consume #{i+1}/{num_consumes}...")
    ocean.assets.pay_for_access_service(ddo, {"from": alice})
    #don't need to call e.g. ocean.assets.download_asset() since wash-consuming
```

## 6. Collect OCEAN rewards

In the same Python console:

```python
#simulate passage of time, until next Thursday, which is the start of DF(X+1)
WEEK = 7 * 86400 # seconds in a week

latest_block = web3.eth.get_block("latest")
t0 = latest_block.timestamp
t1 = t0 // WEEK * WEEK + WEEK
t2 = t1 + WEEK
provider.make_request("evm_increaseTime", [(t1 - t0)])

#Rewards can be claimed via code or webapp, at your leisure. Let's do it now.
OCEAN_before = from_wei(OCEAN.balanceOf(alice))
ocean.ve_fee_distributor.claim({
    "from": alice,
    "gas": latest_block.gasLimit,
    "gasPrice": math.ceil(latest_block["baseFeePerGas"] * 1.2),
})
OCEAN_after = from_wei(OCEAN.balanceOf(alice))
print(f"Just claimed {OCEAN_after - OCEAN_before} OCEAN rewards")
```

## 7. Repeat steps 1-6, for Eth mainnet

First, you'll need to set up remotely. This will be like [setup-remote.md](setup-remote.md), but for Eth mainnet.

We leave this as an exercise to the reader:)

Happy Data Farming!


## Appendix.

At the beginning of this flows, we created an `ocean` object, which is an instance of class [`Ocean`](https://github.com/oceanprotocol/ocean.py/blob/main/ocean_lib/ocean/ocean.py).

It provides convenient access to [DF](https://github.com/oceanprotocol/ocean.py/tree/main/ocean_lib/models/df) & [VE](https://github.com/oceanprotocol/ocean.py/tree/main/ocean_lib/models/ve) Python objects that which wrap [DF](https://github.com/oceanprotocol/contracts/tree/main/contracts/df) & [VE](https://github.com/oceanprotocol/contracts/tree/main/contracts/ve) Solidity contracts:
- `ocean.ve_ocean` or `ocean.veOCEAN -> VeOcean`
- `ocean.df_rewards -> DFRewards`
- `ocean.df_strategy_v1 -> DFStrategyV1`
- `ocean.smart_wallet_checker -> SmartWalletChecker`
- `ocean.ve_allocate -> VeAllocate`
- `ocean.ve_delegation -> VeDelegation`
- `ocean.ve_fee_distributor -> VeFeeDistributor`
- `ocean.ve_fee_estimate(self) -> VeFeeEstimate`




================================================
FILE: READMEs/gas-strategy-remote.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

# Quickstart: Use Specific Gas Strategy for Remote Networks

This quickstart illustrates the definition of gas strategy in ocean-lib stack in order to
confirm the transactions on blockchain as soon as possible in case the network is congested.

Here are the steps:

1.  Setup
2.  Define gas strategy
3.  Alice publishes the asset using gas strategy

Let's go through each step.

## 1. Setup

Ensure that you've already (a) [installed Ocean](install.md), and (b) [set up remotely](setup-remote.md).

## 2. Define gas strategy

Fees are defined for `polygon` & `mumbai` networks.

```python
from ocean_lib.web3_internal.utils import get_gas_fees

priority_fee, max_fee = get_gas_fees()
```

## 3. Alice publishes the asset using gas strategy

The gas strategy can be added to any `tx_dict`, and this is just an example of usage.
```python
#data info
name = "Branin dataset"
url = "https://raw.githubusercontent.com/trentmc/branin/main/branin.arff"
tx_dict = {
        "from": alice,
        "maxPriorityFeePerGas": priority_fee,
        "maxFeePerGas": max_fee,
}

#create data asset
(data_nft, datatoken, ddo) = ocean.assets.create_url_asset(
    name,
    url,
    tx_dict=tx_dict
)

#print
print("Just published a data asset:")
print(f"  data_nft: symbol={data_nft.symbol}, address={data_nft.address}")
print(f"  datatoken: symbol={datatoken.symbol}, address={datatoken.address}")
print(f"  did={ddo.did}")
```



================================================
FILE: READMEs/install.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->
# Install Ocean

## Prerequisites

-   Linux, MacOS, or Windows
-   [Docker](https://docs.docker.com/engine/install/), [Docker Compose](https://docs.docker.com/compose/install/), [allowing non-root users](https://www.thegeekdiary.com/run-docker-as-a-non-root-user/)
-   Python 3.8.5 - Python 3.10.4, Python 3.11 with some manual alterations

## Install ocean.py library

(If you have issues, see "Potential issues & workarounds" section below.)

In a new console:

```console
# Create your working directory
mkdir my_project
cd my_project

# Initialize virtual environment and activate it. Install artifacts.
# Make sure your Python version inside the venv is >=3.8.
# Anaconda is not fully supported for now, please use venv
python3 -m venv venv
source venv/bin/activate

# Avoid errors for the step that follows
pip install wheel

# Install Ocean library.
pip install ocean-lib
```

## Potential issues & workarounds

Issue: M1 * `coincurve` or `cryptography`
- If you have an Apple M1 processor, `coincurve` and `cryptography` installation may fail due missing packages, which come pre-packaged in other operating systems.
- Workaround: ensure you have `autoconf`, `automake`, `libtool` and `pkg-config` installed, e.g. using Homebrew or MacPorts.

Issue: Could not build wheels for coincurve
- Reasons for this happening are usually missing dependencies.
- Workaround:
  - make sure you have the OS-level development libraries for building Python packages: `python3-dev` and `build-essential` (install e.g. using apt-get)
  - install the OS-level `libsecp256k1-dev` library (e.g. using apt-get)
  - install pyproject.toml separately, e.g. `pip install pyproject-toml`
  - if ocean-lib installation still fails, install coincurve separately e.g. `pip install coincurve`, then retry

Issue: MacOS "Unsupported Architecture"
- If you run MacOS, you may encounter an "Unsupported Architecture" issue.
- Workaround: install including ARCHFLAGS: `ARCHFLAGS="-arch x86_64" pip install ocean-lib`. [Details](https://github.com/oceanprotocol/ocean.py/issues/486).

Issue: Dependencies and Python 3.11

- ocean.py depends on the `parsimonious` package. In turn, `parsimonious` depends on `getargsspec`, which doesn't support Python 3.11. The workaround: open the package's expressions.py file (e.g. in ./venv/lib/python3.11/site-packages/parsimonious/expressions.py), and change the line `import getfullargspec as getargsspec` instead of the regular import.

## Next step

You've now installed Ocean, great!

Next step is setup:
- [Remote](setup-remote.md) (Win, MacOS, Linux)
- *or* [Local](setup-local.md) (Linux only)



================================================
FILE: READMEs/key-value-private.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

# Quickstart: Private Sharing of On-Chain Data

## Introduction
This quickstart describes how to use Ocean data NFTs to publish data on-chain, then privately share it to multiple parties.

It can be used for:
1. **Sharing AI models** of small to medium size, to specified parties.
2. **Sharing AI model predictions** to specified parties.
3. **["Soulbound Tokens"](https://papers.ssrn.com/sol3/Delivery.cfm/SSRN_ID4105763_code1186331.pdf?abstractid=4105763&mirid=1)** approach to Web3 identity, where an individual's attributes are fields in one (or more) data NFTs.
4. **Profile NFTs / "Login with Web3"** where a Dapp accesses userdata. In this case, the code would be running in the browser via [pyscript](https://www.pyscript.org); or it would be an equivalent flow using JS not Python. This can be viewed as a special case of (2).

To generalize, this flow is appropriate for:
- **Small to medium-sized datasets.** For larger datasets, store the data off-chain and share via Ocean datatokens.
- **When the data sharer knows (or can compute) the recipient's public key.** When this isn't known - such as for faucets to serve free data to anyone, or for selling priced data to anyone, then use Ocean datatokens.

## Steps

The quickstart follows these steps, for an example of privately sharing an AI model.

Steps by AI modeler (Alice):
1. Setup
2. Publish data NFT
3. Encrypt & store on-chain AI model
4. Share encryption key via chain

Steps by AI model retriever (Bob):
5. Get encryption key via chain
6. Retrieve from chain & decrypt AI model

## 1. Setup

Ensure that you've already (a) [installed Ocean](install.md), and (b) [set up locally](setup-local.md) or [remotely](setup-remote.md).

## 2. Publish data NFT

Here, we publish a data NFT like elsewhere. To make it a soulbound token (SBT). we set `transferable=False`.

In the Python console:
```python
# Publish an NFT token. Note "transferable=False"
data_nft = ocean.data_nft_factory.create({"from": alice}, 'NFT1', 'NFT1', transferable=False)
```

## 3. Encrypt & store on-chain AI model

Here, we'll symmetrically encrypt an AI model, then store it as a key-value pair in a data NFT on-chain.

In the Python console:
```python
# Key-value pair
model_label = "my_MLP"
model_value = "<insert MLP weights here>"

# Compute a symmetric key: unique to this (nft, nft field) and (your priv key)
# Therefore you can calculate it anytime
from ocean_lib.ocean import crypto
symkey = crypto.calc_symkey(data_nft.address + model_label + alice._private_key.hex())

# Symmetrically encrypt AI model
model_value_symenc = crypto.sym_encrypt(model_value, symkey)

# Save model to chain
data_nft.set_data(model_label, model_value_symenc, {"from": alice})
```

## 4. Share encryption key via chain

There are many possible ways for Alice to share the symkey to Bob. Here, Alice shares it securely on a public channel by encrypting the symkey in a way that only Bob can decrypt:
- The public channel is on the same data NFT, on-chain
- So that only Bob can decrypt: Alice asymetricallys encrypt the symkey with Bob's public key, for Bob to decrypt with his private key.

In the Python console:
```python
# Get Bob's public key. There are various ways; see appendix.
pubkey = crypto.calc_pubkey(bob._private_key.hex())

# Asymmetrically encrypt symkey, using Bob's public key
symkey_asymenc = crypto.asym_encrypt(symkey, pubkey)

# Save asymetrically-encrypted symkey to chain
data_nft.set_data("symkey", symkey_asymenc, {"from": alice})
```


## 5. Get encryption key via chain

Whereas the first four steps were done by the AI model sharer (Alice), the remaining steps are done by the AI model receiver (Bob). You're now Bob.

In the Python console:
```python
# Retrieve the asymetrically-encrypted symkey from chain
symkey_asymenc2 = data_nft.get_data("symkey")

# Asymetrically decrypt symkey, with Bob's private key
symkey2 = crypto.asym_decrypt(symkey_asymenc2, bob._private_key.hex())
```

## 6. Retrieve from chain & decrypt AI model

In the Python console:
```python
# Retrieve the symetrically-encrypted model from chain
model_value_symenc2 = data_nft.get_data(model_label)

# Symetrically-decrypt the model, with the symkey retrieved in step 5
model_value2 = crypto.sym_decrypt(model_value_symenc2, symkey2)

print(f"Loaded model {model_label} = {model_value2}")
```


## Appendix

Step 4 gave one way for Alice to get the Dapp's public key; step 5 gave one way for the Dapp to get the encrypted symkey. Here are more options.

On computing public keys:
- If you have the private_key, you can compute the public_key (used above)
- Hardware wallets don't expose private_keys. And, while they do expose a _root_ public_key, you shouldn't publicly share those because it lets anyone see all your wallets
- However, you _can_ compute anyone's public_key from any tx. This is a general solution. Conveniently, Etherscan shows it too.

Possible ways for Alice to get Dapp's public key:
- Alice auto-computes from any of Dapp's previous txs.
- Alice retrieves it from a public-ish registry or api, e.g. etherscan
- Dapp computes it from private_key or from past tx, then shares.

Possible ways for Alice to share an encrypted symkey, or for Dapp to share public_key:
- Directly client-side
  - Client-side: in a browser with Metamask - [example by FELToken](https://betterprogramming.pub/exchanging-encrypted-data-on-blockchain-using-metamask-a2e65a9a896c). This is a good choice because it does no on-chain txs.
  - Client-side: in a script. Like done in step 4 above for public key
- Over a public channel:
  - Public channel: write a new key-value pair on the same data NFT. Like done in step 5 above for encrypted symkey. This is a good choice because the Dapp can access the info in future sessions without extra work.
  - Public channel: a new data NFT for each message
  - Public channel: traditional: http, email, or any messaging medium




================================================
FILE: READMEs/key-value-public.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

# Quickstart: On-Chain Key-Value Store for Public Sharing

Data NFTs can store arbitrary key-value pairs, to be an on-chain key-value store.

They can be used for:
1. **Publicly sharing AI models** of small to medium size
2. **Publicly sharing AI model predictions**
3. **Comments & ratings in Dapps**
4. **Digital Attestations**, e.g. for verifiable credentials

This flow is appropriate for:
- **Public data**. The next README will explore for private sharing.
- **Small to medium-sized datasets.** For larger datasets, store the data off-chain and share via Ocean datatokens.

Here are the steps:

1. Setup
2. Publish data NFT
3. Add key-value pair to data NFT
4. Retrieve value from data NFT

## 1. Setup

Ensure that you've already (a) [installed Ocean](install.md), and (b) [set up locally](setup-local.md) or [remotely](setup-remote.md).

## 2. Publish data NFT

In Python console:
```python
data_nft = ocean.data_nft_factory.create({"from": alice}, 'NFT1', 'NFT1')
```

## 3. Add key-value pair to data NFT

```python
# Key-value pair
model_key = "my_MLP"
model_value = "<insert MLP weights here>"

# set
data_nft.set_data(model_key, model_value, {"from": alice})
```

## 4. Retrieve value from data NFT

```python
model_value2 = data_nft.get_data(model_key)
print(f"Found that {model_key} = {model_value2}")
```

This data is public, so anyone can retrieve it.

That's it! Note the simplicity. All data was stored and retrieved from on-chain. We don't need Ocean Provider or Ocean Aquarius for these use cases (though the latter can help for fast querying & retrieval).

Under the hood, it uses [ERC725](https://erc725alliance.org/), which augments ERC721 with a well-defined way to set and get key-value pairs.

## 5. Next step

This README showed how to share _public_ key-value data. The next README covers private data. [Let's go there!](key-value-private.md).


================================================
FILE: READMEs/main-flow.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

# Main flow

This step is the fun one! In it, you'll publish a data asset, post for free / for sale, dispense it / buy it, and consume it.

We assume you've already (a) [installed Ocean](install.md), and (b) done [local setup](setup-local.md) or [remote setup](setup-remote.md). This flow works for either one, without any changes between them (!)

Steps in the flow:
1. Alice publishes dataset
2. Bob gets access to the dataset (faucet, priced, etc)
3. Bob consumes the dataset

Let's go!

## 1. Alice publishes dataset

In the same Python console:
```python
#data info
name = "Branin dataset"
url = "https://raw.githubusercontent.com/trentmc/branin/main/branin.arff"

#create data asset
(data_nft, datatoken, ddo) = ocean.assets.create_url_asset(name, url, {"from": alice})

#print
print("Just published asset:")
print(f"  data_nft: symbol={data_nft.symbol}, address={data_nft.address}")
print(f"  datatoken: symbol={datatoken.symbol}, address={datatoken.address}")
print(f"  did={ddo.did}")
```

You've now published an Ocean asset!
- `data_nft` is the base (base IP)
- `datatoken` for access by others (licensing)
- `ddo` holding metadata


(For more info, see [Appendix: Publish Details](#appendix-publish-details).)

## 2. Bob gets access to the dataset

Bob wants to consume the dataset that Alice just published. The first step is for Bob to get 1.0 datatokens. Below, we show four possible approaches:
- A & B are when Alice is in contact with Bob. She can mint directly to him, or mint to herself and transfer to him.
- C is when Alice wants to share access for free, to anyone
- D is when Alice wants to sell access

In the same Python console:
```python
from ocean_lib.ocean.util import to_wei

#Approach A: Alice mints datatokens to Bob
datatoken.mint(bob, to_wei(1), {"from": alice})

#Approach B: Alice mints for herself, and transfers to Bob
datatoken.mint(alice, to_wei(1), {"from": alice})
datatoken.transfer(bob, to_wei(1), {"from": alice})

#Approach C: Alice posts for free, via a dispenser / faucet; Bob requests & gets
datatoken.create_dispenser({"from": alice})
datatoken.dispense(to_wei(1), {"from": bob})

#Approach D: Alice posts for sale; Bob buys
# D.1 Alice creates exchange
price = to_wei(100)
exchange = datatoken.create_exchange({"from": alice}, price, ocean.OCEAN_address)

# D.2 Alice makes 100 datatokens available on the exchange
datatoken.mint(alice, to_wei(100), {"from": alice})
datatoken.approve(exchange.address, to_wei(100), {"from": alice})

# D.3 Bob lets exchange pull the OCEAN needed
OCEAN_needed = exchange.BT_needed(to_wei(1), consume_market_fee=0)
ocean.OCEAN_token.approve(exchange.address, OCEAN_needed, {"from":bob})

# D.4 Bob buys datatoken
exchange.buy_DT(to_wei(1), consume_market_fee=0, tx_dict={"from": bob})
````

(For more info, see [Appendix: Dispenser / Faucet Details](#appendix-faucet-details) and [Exchange Details](#appendix-exchange-details).)

## 3. Bob consumes the dataset

Bob now has the datatoken for the dataset! Time to download the dataset and use it.

In the same Python console:
```python
# Bob sends a datatoken to the service to get access
order_tx_id = ocean.assets.pay_for_access_service(ddo, {"from": bob}).hex()

# Bob downloads the file. If the connection breaks, Bob can try again
asset_dir = ocean.assets.download_asset(ddo, bob, './', order_tx_id)

import os
file_name = os.path.join(asset_dir, "file0")
```

Let's check that the file is downloaded. In a new console:

```console
cd my_project/datafile.did:op:*
cat file0
```
The *beginning* of the file should contain the following contents:
```
% 1. Title: Branin Function
% 3. Number of instances: 225
% 6. Number of attributes: 2

@relation branin

@attribute 'x0' numeric
@attribute 'x1' numeric
@attribute 'y' numeric

@data
-5.0000,0.0000,308.1291
-3.9286,0.0000,206.1783
...
```

(For more info, see [Appendix: Consume Details](#appendix-consume-details).)

## Next step

You've now gone through the main flow for Ocean, congrats!

Where you want to go next is up to you! Some possibilities:
- Go back to the [top-level README](../README.md) to explore advanced flows like Compute-to-Data, Predict-ETH, and Data Farming
- Review this README's appendices, which expand on the steps above with further flexibility.


<h2 id="appendix-publish-details">Appendix: Publish Details</h4>

### Reconstructing Data NFT & Datatoken

Anytime in the future, you can reconstruct your data NFT as an object in Python, via:

```console
from ocean_lib.models.data_nft import DataNFT
config = <like shown elsewhere in READMEs>
data_nft_address = <what you wrote down previously>
data_nft = DataNFT(config, data_nft_address)
```

It's similar for Datatokens. In Python:

```console
from ocean_lib.models.datatoken_base import DatatokenBase
config = <like shown elsewhere in READMEs>
datatoken_address = <what you wrote down previously>
datatoken = DatatokenBase.get_typed(config, datatoken_address)
```

### Data NFT Interface

Data NFTs implement ERC721 functionality, ERC725 which extends it, and data management functionality on top.

ERC721:
- Basic spec of a non-fungible token (NFT)
- Official spec is at [erc721.org](https://erc721.org/)
- Solidity interface: [IERC721Template.sol](https://github.com/oceanprotocol/contracts/blob/main/contracts/interfaces/IERC721Template.sol)

ERC725:
- ERC725X is execution, and Y is key-value store
- Official spec is at [eips.ethereum.org](https://eips.ethereum.org/EIPS/eip-725)
- Solidity interface: [IERC725X.sol](https://github.com/oceanprotocol/contracts/blob/main/contracts/interfaces/IERC725X.sol) (execution) and [IERC725Y.sol](https://github.com/oceanprotocol/contracts/blob/main/contracts/interfaces/IERC725Y.sol) (key-value store)

The `data_nft` is a Python object of class [DataNFT](https://github.com/oceanprotocol/ocean.py/blob/main/ocean_lib/models/data_nft.py). The DataNFT class directly exposes the Solidity ERC721 & ERC725 interfaces. This means your `data_nft` object has a Python method for every Solidity method!

Besides that, DataNFT implements other Python methods like `create_datatoken()` to improve developer experience. And, [ocean_assets.OceanAssets](https://github.com/oceanprotocol/ocean.py/blob/main/ocean_lib/ocean/ocean_assets.py) and other higher-level Python classes / methods work with DataNFT.

Ocean's architecture allows for >1 implementations of ERC721, each with its own Solidity template and Python class. Here are the templates:
- [ERC721Template.sol](https://github.com/oceanprotocol/contracts/blob/main/contracts/templates/ERC721Template.sol), exposed as Python class `DataNFT`
- (there's just one template so far; we can expect more in the future)

### Datatoken Interface

Datatokens implement ERC20 functionality, and data management functionality on top.

ERC20:
- Basic spec of a fungible token standard
- Official spec is at [eips.ethereum.org](https://eips.ethereum.org/EIPS/eip-20)
- Solidity interface: [IERC20Template.sol](https://github.com/oceanprotocol/contracts/blob/main/contracts/interfaces/IERC20Template.sol)

Ocean's architecture allows for >1 implementations of ERC20, each with its own "template". Here are the templates so far (we can expect more over time).

Template 1:
- Solidity: [ERC20Template.sol](https://github.com/oceanprotocol/contracts/blob/main/contracts/templates/ERC20Template.sol)
- Python wrapper: [Datatoken1](https://github.com/oceanprotocol/ocean.py/blob/main/ocean_lib/models/datatoken.py). It has a Python method for every Solidity method.
- Implements methods like `start_order()`, `create_exchange()`, and `create_dispenser()` to enhance developer experience.

Template 2:
- Inherits from template 1 in both Solidity and Python.
- Solidity: [ERC20TemplateEnterprise.sol](https://github.com/oceanprotocol/contracts/blob/main/contracts/templates/ERC20TemplateEnterprise.sol)
- Python wrapper: [Datatoken2](https://github.com/oceanprotocol/ocean.py/blob/main/ocean_lib/models/datatoken2.py)
- New method: [`buy_DT_and_order()`](https://github.com/oceanprotocol/ocean.py/blob/4aa12afd8a933d64bc2ed68d1e5359d0b9ae62f9/ocean_lib/models/datatoken2.py#L20). This uses just 1 tx to do both actions at once (versus 2 txs for template 1).
- New method: [`dispense_and_order()`](https://github.com/oceanprotocol/ocean.py/blob/4aa12afd8a933d64bc2ed68d1e5359d0b9ae62f9/ocean_lib/models/datatoken2.py#L70). Similarly, uses just 1 tx.

Below you can find an explanatory table describing the template attributes:

Template # | Class Label | Allows dispense by default? | Allows non-custody of datatokens? | Combines txs? | Allows non-custody of url?
:----: | :----: | :----: | :----: | :----: | :----:
1 | Datatoken1 | Y | N | N | N
2 | Datatoken2 | N | Y | Y | N


### DIDs and DDOs

DDOs get returned in `create()` calls. Think of them as metadata, following a well-defined format.

Let's get more specific. A [DID](https://w3c-ccg.github.io/did-spec/) is a decentralized identifier. A DID Document (DDO) is a JSON blob that holds information about the DID. Given a DID, a resolver will return the DDO of that DID.

An Ocean _asset_ has a DID and DDO, alongside a data NFT and >=0 datatokens. The DDO should include metadata about the asset, and define access in at least one service. Only owners or delegated users can modify the DDO.

DDOs follow a schema - a pre-specified structure of possible metadata fields.

Ocean Aquarius helps in reading, decrypting, and searching through encrypted DDO data from the chain.

[Ocean docs](https://docs.oceanprotocol.com/core-concepts/did-ddo) have further info yet.

### Publish Flexibility

Here's an example similar to the `create()` step above, but exposes more fine-grained control.

In the same python console:
```python
# Specify metadata and services, using the Branin test dataset
date_created = "2021-12-28T10:55:11Z"
metadata = {
    "created": date_created,
    "updated": date_created,
    "description": "Branin dataset",
    "name": "Branin dataset",
    "type": "dataset",
    "author": "Trent",
    "license": "CC0: PublicDomain",
}

# Use "UrlFile" asset type. (There are other options)
from ocean_lib.structures.file_objects import UrlFile
url_file = UrlFile(
    url="https://raw.githubusercontent.com/trentmc/branin/main/branin.arff"
)

# Publish data asset
from ocean_lib.models.datatoken_base import DatatokenArguments
_, _, ddo = ocean.assets.create(
    metadata,
    {"from": alice},
    datatoken_args=[DatatokenArguments(files=[url_file])],
)
```


### DDO Encryption or Compression

The DDO is stored on-chain. It's encrypted and compressed by default. Therefore it supports GDPR "right-to-be-forgotten" compliance rules by default.

You can control this during create():
- To disable encryption, use `ocean.assets.create(..., encrypt_flag=False)`.
- To disable compression, use `ocean.assets.create(..., compress_flag=False)`.
- To disable both, use `ocean.assets.create(..., encrypt_flag=False, compress_flag=False)`.


### Create _just_ a data NFT

Calling `create()` like above generates a data NFT, a datatoken for that NFT, and a ddo. This is the most common case. However, sometimes you may want _just_ the data NFT, e.g. if using a data NFT as a simple key-value store. Here's how:
```python
data_nft = ocean.data_nft_factory.create({"from": alice}, 'NFT1', 'NFT1')
```

If you call `create()` after this, you can pass in an argument `data_nft_address:string` and it will use that NFT rather than creating a new one.

### Create a datatoken from a data NFT

Calling `create()` like above generates a data NFT, a datatoken for that NFT, and a ddo object. However, we may want a second datatoken. Or, we may have started with _just_ the data NFT, and want to add a datatoken to it. Here's how:

```python
datatoken = data_nft.create_datatoken({"from": alice}, "Datatoken 1", "DT1")
```

If you call `create()` after this, you can pass in an argument `deployed_datatokens:List[Datatoken1]` and it will use those datatokens during creation.

<h2 id="appendix-faucet-details">Appendix: Dispenser / Faucet Details</h4>


### Dispenser Interface

We access dispenser (faucet) functionality from two complementary places: datatokens, and `Dispenser` object.

A given datatoken can create exactly one dispenser for that datatoken.

**Interface via datatokens:**
- [`datatoken.create_dispenser()`](https://github.com/oceanprotocol/ocean.py/blob/4aa12afd8a933d64bc2ed68d1e5359d0b9ae62f9/ocean_lib/models/datatoken.py#L337) - implemented in DatatokenBase, inherited by Datatoken2
- [`datatoken.dispense()`](https://github.com/oceanprotocol/ocean.py/blob/4aa12afd8a933d64bc2ed68d1e5359d0b9ae62f9/ocean_lib/models/datatoken.py#L380) - ""
- [`datatoken.dispense_and_order()` - implemented in Datatoken1](https://github.com/oceanprotocol/ocean.py/blob/4aa12afd8a933d64bc2ed68d1e5359d0b9ae62f9/ocean_lib/models/datatoken.py#L439) and [in Datatoken2](https://github.com/oceanprotocol/ocean.py/blob/4aa12afd8a933d64bc2ed68d1e5359d0b9ae62f9/ocean_lib/models/datatoken_enterprise.py#L70). The latter only needs one tx to dispense and order.
- [`datatoken.dispenser_status()`](https://github.com/oceanprotocol/ocean.py/blob/4aa12afd8a933d64bc2ed68d1e5359d0b9ae62f9/ocean_lib/models/datatoken.py#L403) - returns a [`DispenserStatus`](https://github.com/oceanprotocol/ocean.py/blob/4aa12afd8a933d64bc2ed68d1e5359d0b9ae62f9/ocean_lib/models/dispenser.py#L16) object

**Interface via [`Dispenser`](https://github.com/oceanprotocol/ocean.py/blob/main/ocean_lib/models/dispenser.py) Python class:**
- You can access its instance via `ocean.dispenser`.
- `Dispenser` wraps [Dispenser.sol](https://github.com/oceanprotocol/contracts/blob/main/contracts/pools/dispenser/Dispenser.sol) Solidity implementation, to expose `Dispenser.sol`'s methods as Python methods.
- Note that `Dispenser` is _global_ across all datatokens. Therefore calls to the Solidity contract - or Python calls that pass through - provide the datatoken address as an argument.
- Example call: `ocean.dispenser.setAllowedSwapper(datatoken_addr, ZERO_ADDRESS, {"from": alice})`

### Flexibility in Creating a Dispenser

`datatoken.create_dispenser()` can take these optional arguments:
- `max_tokens` - maximum number of tokens to dispense. The default is a large number.
- `max_balance` - maximum balance of requester. The default is a large number.
- `with_mint` - allow minting
- `allowed_swapper` - swapper user address

A call would look like `create_dispenser({"from": alice}, max_tokens=max_tokens, max_balance=max_balance)`.


### Dispenser Status

To learn about dispenser status:

```python
status = datatoken.dispenser_status()
print(f"For datatoken {datatoken.address}:")
print(status)
```

It will output something like:
```text
For datatoken 0x92cA723B61CbD933390aA58b83e1F00cedf4ebb6:
DispenserStatus:
  active = True
  owner_address = 0x1234
  is_minter = True
  max_tokens = 1000 (10000000000000000000000 wei)
  max_balance = 10  (100000000000000000000 wei)
  balance = 1
  allowed_swapper = anyone can request
```

### Who can request tokens from a faucet

Template 1 (`Datatoken1`):
- Anyone can call `datatoken.dispense()` to request tokens.

Template 2 (`Datatoken2`):
- Option A. Anyone can `datatoken.dispense_and_order()` to request tokens, and order.
- Option B. Not anyone can call `datatoken.dispense()` by default. To allow anyone, the publisher does: `ocean.dispenser.setAllowedSwapper(datatoken_address, ZERO_ADDRESS, {"from" : publisher_wallet})`, where `ZERO_ADDRESS` is `0x00..00`.

Details: `Dispenser.sol` has an attribute `allowed_swapper` to govern who can call `dispense()`. A value of `0x00...0` allows anyone. Template 1 has `ZERO_ADDRESS` as a default value; template 2 does not. However, template 2 allows anyone to call `dispense_and_order()`, independent of the value of `allowed_swapper`.

<h2 id="appendix-exchange-details">Appendix: Exchange Details</h4>

### Exchange Interface

We access exchange functionality from three complementary places: datatokens, [`OneExchange`](https://github.com/oceanprotocol/ocean.py/blob/4aa12afd8a933d64bc2ed68d1e5359d0b9ae62f9/ocean_lib/models/fixed_rate_exchange.py#L117) object, and (if needed) [`FixedRateExchange`](https://github.com/oceanprotocol/ocean.py/blob/4aa12afd8a933d64bc2ed68d1e5359d0b9ae62f9/ocean_lib/models/fixed_rate_exchange.py#L106) object.

A given datatoken can create one or more `OneExchange` objects.

**Interface via datatokens:**
- [`datatoken.create_exchange()`](https://github.com/oceanprotocol/ocean.py/blob/4aa12afd8a933d64bc2ed68d1e5359d0b9ae62f9/ocean_lib/models/datatoken.py#L237) - Returns a `OneExchange` object.
- [`datatoken.get_exchanges()`](https://github.com/oceanprotocol/ocean.py/blob/4aa12afd8a933d64bc2ed68d1e5359d0b9ae62f9/ocean_lib/models/datatoken.py#L312) - Returns a list of `OneExchange` objects.

Once you've got a `OneExchange` object, most interactions are with it.

**Interface via [`OneExchange`](https://github.com/oceanprotocol/ocean.py/blob/4aa12afd8a933d64bc2ed68d1e5359d0b9ae62f9/ocean_lib/models/fixed_rate_exchange.py#L117) Python class:**
- [`BT_needed()`](https://github.com/oceanprotocol/ocean.py/blob/4aa12afd8a933d64bc2ed68d1e5359d0b9ae62f9/ocean_lib/models/fixed_rate_exchange.py#L150) - # basetokens (BTs) needed, to buy target # datatokens (DTs)
- [`BT_received()`](https://github.com/oceanprotocol/ocean.py/blob/4aa12afd8a933d64bc2ed68d1e5359d0b9ae62f9/ocean_lib/models/fixed_rate_exchange.py#L167) - # BTs you receive, in selling given # DTs
- [`buy_DT()`](https://github.com/oceanprotocol/ocean.py/blob/4aa12afd8a933d64bc2ed68d1e5359d0b9ae62f9/ocean_lib/models/fixed_rate_exchange.py#L184) - spend BTs to buy DTs
- [`sell_DT()`](https://github.com/oceanprotocol/ocean.py/blob/4aa12afd8a933d64bc2ed68d1e5359d0b9ae62f9/ocean_lib/models/fixed_rate_exchange.py#L230) - sell DTs, receive back BTs
- and more, including get/set rate (price), toggle on/off, get/set fees, update balances

While most interactions are with `OneExchange` described above, sometimes we may want to access the `FixedRateExchange` object.

**Interface via [`FixedRateExchange`](https://github.com/oceanprotocol/ocean.py/blob/4aa12afd8a933d64bc2ed68d1e5359d0b9ae62f9/ocean_lib/models/fixed_rate_exchange.py#L106) Python class:**
- You can access its instance via `ocean.fixed_rate_exchange`.
- `FixedRateExchange` wraps [FixedRateExchange.sol](https://github.com/oceanprotocol/contracts/blob/main/contracts/pools/fixedRate/FixedRateExchange.sol) Solidity implementation, to expose `Dispenser.sol`'s methods as Python methods.
- Note that `FixedRateExchange` is _global_ across all datatokens. Therefore calls to the Solidity contract - or Python calls that pass through - provide the exchange id address as an argument. It's exchange id, and not datatoken, because there may be >1 exchange for a given datatoken.
- Example call: `ocean.fixed_rate_exchange.getRate(exchange_id)` returns rate (price).

### Flexibility in Creating an Exchange

When Alice posted the dataset for sale via `create_exchange()`, she used OCEAN. Alternatively, she could have used H2O, the OCEAN-backed stable asset. Or, she could have used USDC, DAI, RAI, WETH, or other, for a slightly higher fee (0.2% vs 0.1%).

### Exchange Status

Here's how to see all the exchanges that list the datatoken. In the Python console:
```python
exchanges = datatoken.get_exchanges() # list of OneExchange
```

To learn more about the exchange status:

```python
print(exchange.details)
print(exchange.exchange_fees_info)
```

It will output something like:
```text
>>> print(exchange.details)
ExchangeDetails:
  datatoken = 0xdA3cf7aE9b28E1A9B5F295201d9AcbEf14c43019
  base_token = 0x24f42342C7C171a66f2B7feB5c712471bED92A97
  fixed_rate (price) = 1.0 (1000000000000000000 wei)
  active = True
  dt_supply = 99.0 (99000000000000000000 wei)
  bt_supply = 1.0 (1000000000000000000 wei)
  dt_balance = 0.0 (0 wei)
  bt_balance = 1.0 (1000000000000000000 wei)
  with_mint = False
  dt_decimals = 18
  bt_decimals = 18
  owner = 0x02354A1F160A3fd7ac8b02ee91F04104440B28E7

>>> print(exchange.exchange_fees_info)
ExchangeFeeInfo:
  publish_market_fee = 0.0 (0 wei)
  publish_market_fee_available = 0.0 (0 wei)
  publish_market_fee_collector = 0x02354A1F160A3fd7ac8b02ee91F04104440B28E7
  opc_fee = 0.001 (1000000000000000 wei)
  ocean_fee_available (to opc) = 0.001 (1000000000000000 wei)
```


<h2 id="appendix-create-bundled">Create asset and pricing schema simultaneously </h2>
Ocean Assets allows you to bundle several common scenarios as a single transaction, thus lowering gas fees.

Any of the `ocean.assets.create_<type>_asset()` functions can also take an optional parameter that describes a bundled pricing schema (Dispenser or Fixed Rate Exchange).
This can be either a DispenserArguments or an ExchangeArguments object. The parameters for these Arguments classes are identical to those for creating the object itself.
E.g. adding `pricing_schema_args=DispenserArguments(to_wei(1), to_wei(1))` to the `create` function is equivalent to performing the creation and creating a dispenser later using `dt.create_dispenser(to_wei(1), to_wei(1))`.

Here is an example involving an exchange:

```python
from ocean_lib.models.fixed_rate_exchange import ExchangeArguments
(data_nft, datatoken, ddo) = ocean.assets.create_url_asset(
    name,
    url,
    {"from": alice},
    pricing_schema_args=ExchangeArguments(rate=to_wei(3), base_token_addr=ocean.OCEAN_address, dt_decimals=18)
)

assert len(datatoken.get_exchanges()) == 1
```

<h2 id="appendix-consume-details">Appendix: Consume Details</h2>

### Consume General

To "consume" an asset typically means placing an "order", where you pass in 1.0 datatokens and get back a url. Then, you typically download the asset from the url.

For more information, search for "order" in this README or related code.

### About ARFF format

The file is in ARFF format, used by some AI/ML tools. Our example has two input variables (x0, x1) and one output.

```console
% 1. Title: Branin Function
% 3. Number of instances: 225
% 6. Number of attributes: 2

@relation branin

@attribute 'x0' numeric
@attribute 'x1' numeric
@attribute 'y' numeric

@data
-5.0000,0.0000,308.1291
-3.9286,0.0000,206.1783
...
```

<h2 id="appendix-consume-details">Appendix: Ocean Instance</h2>

At the beginning of most flows, we create an `ocean` object, which is an instance of class [`Ocean`](https://github.com/oceanprotocol/ocean.py/blob/main/ocean_lib/ocean/ocean.py). It exposes useful information, including the following.

Config dict attribute:
- `ocean.config_dict` or `ocean.config -> dict`

OCEAN token:
- `ocean.OCEAN_address -> str`
- `ocean.OCEAN_token` or `ocean.OCEAN -> Datatoken`

Ocean smart contracts:
- `ocean.data_nft_factory -> DataNFTFactoryContract`
- `ocean.dispenser -> Dispenser` - faucets for free data
- `ocean.fixed_rate_exchange -> FixedRateExchange` - exchanges for priced data

Simple getters:
- `ocean.get_nft_token(self, token_address: str) -> DataNFT`
- `ocean.get_datatoken(self, token_address: str) -> Datatoken`
- `ocean.def get_user_orders(self, address: str, datatoken: str)`
- (and some others that are more complex)

It also provides Python wrappers to veOCEAN and Data Farming contracts. See [df.md](df.md) for details.


================================================
FILE: READMEs/parameters.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

# On Config Parameters

We can set any config parameter using the config dictionary.

An `Ocean` instance will hold a `config_dict` that holds various config parameters. These parameters need to get set using the ExampleConfig class. This is set based on what's input to `Ocean` constructor:

1.  dict input: `Ocean({'METADATA_CACHE_URI':..})`, in which case you have to build the web3 instance manually
2.  use boilerplate from example config, which also sets the web3 instance to be used by each contract

## Example

Here is an example for (1): dict input, filled from envvars

```python
import os
from ocean_lib.ocean.ocean import Ocean
from ocean_lib.example_config import get_web3

network_url = "https://your-rpc.com"

d = {
   'METADATA_CACHE_URI': "https://v4.aquarius.oceanprotocol.com",
   'PROVIDER_URL' : "https://v4.provider.goerli.oceanprotocol.com",
   "web3_instance": get_web3(network_url)
}
ocean = Ocean(d)
```

## Further details

For the most precise description of config parameter logic, see the [Ocean() constructor implementation](https://github.com/oceanprotocol/ocean.py/blob/main/ocean_lib/ocean/ocean.py).


================================================
FILE: READMEs/predict-eth.md
================================================
This has been moved [here](https://github.com/oceanprotocol/predict-eth).


================================================
FILE: READMEs/profile-nfts-flow.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

# Quickstart: Profile NFTs

This is a flow showing how to do "login with Web3" with the help of Ocean data NFTs. In this flow, a dapp is not only connected to the user's wallet, but it can access profile data that the user has privately shared to it. Interestingly, these NFTs are also essentially [Soulbound Tokens](https://papers.ssrn.com/sol3/Delivery.cfm/SSRN_ID4105763_code1186331.pdf?abstractid=4105763&mirid=1) as well:)

Here are the steps:

1. Setup
2. Alice publishes data NFT
3. Alice adds key-value pair to data NFT. 'value' encrypted with a symmetric key 'symkey'
4. Alice gets Dapp's public_key
5. Alice encrypts symkey with Dapp's public key and shares to Dapp
6. Dapp gets & decrypts symkey, then gets & decrypts original 'value'

## 1. Setup

Ensure that you've already (a) [installed Ocean](install.md), and (b) [set up locally](setup-local.md) or [remotely](setup-remote.md).

## 2. Alice publishes data NFT

We publish a data NFT like elsewhere, except we set `transferable=False` (and skip print statements).

In the Python console:
```python
# Publish an NFT token. Note "transferable=False"
data_nft = ocean.data_nft_factory.create({"from": alice}, 'NFT1', 'NFT1', transferable=False)
```

## 3. Alice adds key-value pair to data NFT. 'value' encrypted with a symmetric key 'symkey'

```python
# imports
from base64 import b64encode
from cryptography.fernet import Fernet
from eth_account.messages import encode_defunct
from hashlib import sha256
from ocean_lib.web3_internal.utils import sign_with_key
from web3.main import Web3


# Key-value pair
profiledata_name = "fav_color"
profiledata_val = "blue"

# Prep key for setter. Contract/ERC725 requires keccak256 hash
profiledata_name_hash = Web3.keccak(text=profiledata_name)

# Choose a symkey where:
# - sharing it unlocks only this field: make unique to this data nft & field
# - only Alice can compute it: make it a function of her private key
# - is hardware wallet friendly: uses Alice's digital signature not private key
preimage = data_nft.address + profiledata_name
preimage = sha256(preimage.encode('utf-8')).hexdigest()
prefix = "\x19Ethereum Signed Message:\n32"
msg = Web3.solidity_keccak(
    ["bytes", "bytes"], [Web3.to_bytes(text=prefix), Web3.to_bytes(text=preimage)]
)
signed = sign_with_key(msg, alice._private_key.hex())
symkey = b64encode(str(signed).encode('ascii'))[:43] + b'='  # bytes

# Prep value for setter
profiledata_val_encr_hex = Fernet(symkey).encrypt(profiledata_val.encode('utf-8')).hex()

# set
data_nft.setNewData(profiledata_name_hash, profiledata_val_encr_hex, {"from": alice})
```

## 4. Alice gets Dapp's public_key

There are various ways to compute public_key, and for Alice to get it (see Appendix). Here, the Dapp computes public_key from its private_key, then shares with Alice client-side within the script.

```python
from eth_keys import keys
from eth_utils import decode_hex

dapp_private_key = os.getenv('TEST_PRIVATE_KEY2')
dapp_private_key_obj = keys.PrivateKey(decode_hex(dapp_private_key))
dapp_public_key = str(dapp_private_key_obj.public_key)  # str
dapp_address = dapp_private_key_obj.public_key.to_address()  # str
```

## 5. Alice encrypts symkey with Dapp's public key and shares to Dapp

There are various ways for Alice to share the encrypted symkey to the Dapp (see Appendix). Here, Alice writes a new key-value pair on the same data NFT. This approach allows the Dapp to access the info in future sessions without extra work.

```python
from ecies import encrypt as asymmetric_encrypt

symkey_name = (profiledata_name + ':for:' + dapp_address[:10])  # str
symkey_name_hash = Web3.keccak(text=symkey_name)

symkey_val_encr = asymmetric_encrypt(dapp_public_key, symkey)  # bytes

symkey_val_encr_hex = symkey_val_encr.hex()  # hex

# arg types: key=bytes32, value=bytes, wallet=wallet
data_nft.setNewData(symkey_name_hash, symkey_val_encr_hex, {"from": alice})
```

## 6. Dapp gets & decrypts symkey, then gets & decrypts original 'value'

```python
from ecies import decrypt as asymmetric_decrypt

# symkey_name_hash = <Dapp would set like above>
symkey_val_encr2 = data_nft.getData(symkey_name_hash)
symkey2 = asymmetric_decrypt(dapp_private_key, symkey_val_encr2)

# profiledata_name_hash = <Dapp would set like above>
profiledata_val_encr_hex2 = data_nft.getData(profiledata_name_hash)
profiledata_val2_bytes = Fernet(symkey).decrypt(profiledata_val_encr_hex2)
profiledata_val2 = profiledata_val2_bytes.decode('utf-8')

print(f"Dapp found profiledata {profiledata_name} = {profiledata_val2}")
```


## Appendix

Step 4 gave one way for Alice to get the Dapp's public key; step 5 gave one way for the Dapp to get the encrypted symkey. Here are more options.

On computing public keys:
- If you have the private_key, you can compute the public_key (used above)
- Hardware wallets don't expose private_keys. And, while they do expose a _root_ public_key, you shouldn't publicly share those because it lets anyone see all your wallets
- However, you _can_ compute anyone's public_key from any tx. This is a general solution. Conveniently, Etherscan shows it too.

Possible ways for Alice to get Dapp's public key:
- Alice auto-computes from any of Dapp's previous txs.
- Alice retrieves it from a public-ish registry or api, e.g. etherscan
- Dapp computes it from private_key or from past tx, then shares.

Possible ways for Alice to share an encrypted symkey, or for Dapp to share public_key:
- Directly client-side
  - Client-side: in a browser with Metamask - [example by FELToken](https://betterprogramming.pub/exchanging-encrypted-data-on-blockchain-using-metamask-a2e65a9a896c). This is a good choice because it does no on-chain txs.
  - Client-side: in a script. Like done in step 4 above for public key
- Over a public channel:
  - Public channel: write a new key-value pair on the same data NFT. Like done in step 5 above for encrypted symkey. This is a good choice because the Dapp can access the info in future sessions without extra work.
  - Public channel: a new data NFT for each message
  - Public channel: traditional: http, email, or any messaging medium




================================================
FILE: READMEs/publish-flow-credentials.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

# Quickstart: Publish & Metadata update Flows for credentials

This quickstart describes how to use credentials in order to limit access to a dataset.

Ensure that you've already (a) [installed Ocean](install.md), and (b) [set up locally](setup-local.md) or [remotely](setup-remote.md).

Here are the steps:

1.  Publish a dataset that can only be accessed by Alice and Bob. Everyone else will be denied.
2.  Update the dataset so only Bob will be denied, everyone else will have access.


Let's go through each step.

## 2. Carlos publishes the API asset, allowing only Alice and Bob as consumers


```python
url = 'http://www.example.net'
name = "Restricted dataset"
credentials = {
    "allow": [{"type": "address", "values": [alice.address, bob.address]}],
    "deny": [],
}
#create asset
(data_nft, datatoken, ddo) = ocean.assets.create_url_asset(name, url, {"from": carlos}, credentials = credentials)
print(f"Just published asset, with did={ddo.did}")
```


That's it! You've created a data asset which is accesible only to Alice and Bob. Consume here is just like in [consume-flow](consume-flow.md).


## 2. Carlos updates the asset, allowing everyone, but denying Bob

Using the ddo directly, or later using `ddo=ocean.assets.resolve(<DID you wrote down previously>)`

```python
ddo.credentials = {
    "allow": [],
    "deny": [{"type": "address", "values": [bob.address]}],
}
ddo = ocean.assets.update(ddo, {"from": carlos})
```


That's it! Now everyone can access the dataset, except Bob. Consume here is just like in [consume-flow](consume-flow.md).

For more information about credentials, you can refer to [docs](https://docs.oceanprotocol.com/core-concepts/did-ddo#credentials).


================================================
FILE: READMEs/publish-flow-graphql.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

# Quickstart: Publish & Consume Flow for GraphQL data type

This quickstart describes a flow to publish & consume GraphQL-style URIs. In our example, the data asset is a query to find data NFTs via ocean-subgraph.

Here are the steps:

1.  Setup
2.  Publish dataset
3.  Consume dataset

Let's go through each step.

## 1. Setup

Ensure that you've already (a) [installed Ocean](install.md), and (b) [set up locally](setup-local.md) or [remotely](setup-remote.md).

## 2. Publish dataset

In the same Python console:
```python
#data info
name = "Data NFTs in Ocean"
url="https://v4.subgraph.goerli.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph"
query="""query{
               nfts(orderBy: createdTimestamp,orderDirection:desc){
                    id
                    symbol
                    createdTimestamp
                    }
               }
"""

#create asset
(data_nft, datatoken, ddo) = ocean.assets.create_graphql_asset(name, url, query, {"from": alice})
print(f"Just published asset, with did={ddo.did}")
```

That's it! You've created a data asset of "GraphqlQuery" asset type. It includes a data NFT, a datatoken for the data NFT, and metadata.

## 3.  Consume dataset

Consume here is just like in [consume-flow](consume-flow.md). The file downloaded is a .json. From that, use the python `json` library to parse it as desired.



================================================
FILE: READMEs/publish-flow-onchain.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

# Quickstart: Publish & Consume Flow using onchain data source

This quickstart describes a flow to publish & consume onchain data source

Here are the steps:

1.  Setup
2.  Publish dataset
3.  Consume dataset

Let's go through each step.

## 1. Setup

Ensure that you've already (a) [installed Ocean](install.md), and (b) [set up locally](setup-local.md) or [remotely](setup-remote.md).

## 2. Publish dataset

In the same Python console:
```python
#data info
from ocean_lib.ocean.util import get_address_of_type

name = "swapOceanFee function call"
contract_address = get_address_of_type(config, "Router")
contract_abi = {
                "inputs": [],
                "name": "swapOceanFee",
                "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
                "stateMutability": "view",
                "type": "function",
		}

#create asset
(data_nft, datatoken, ddo) = ocean.assets.create_onchain_asset(name, contract_address, contract_abi, {"from": alice})
print(f"Just published asset, with did={ddo.did}")
```

That's it! You've created a data asset of "SmartContractCall" asset type. It includes a data NFT, a datatoken for the data NFT, and metadata.

## 3.  Consume the dataset

(Consume here is just like in [consume-flow](READMEs/consume-flow.md]. The file downloaded is a .json. From that, use the python `json` library to parse it as desired.)


================================================
FILE: READMEs/publish-flow-restapi.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

# Quickstart: Publish & Consume Flow for REST API-style URIs

This quickstart describes a flow to publish Kraken REST API of OCEAN-USD pair price feed, to make it available as free data asset on Ocean, and to consume it.

Here are the steps:

1.  Setup
2.  Alice publishes the API asset
3.  Alice creates a faucet for the asset
4.  Bob gets a free datatoken, then consumes it

Let's go through each step.

## 1. Setup

Ensure that you've already (a) [installed Ocean](install.md), and (b) [set up locally](setup-local.md) or [remotely](setup-remote.md).

## 2. Alice publishes the API asset

In the same Python console:
```python
# Data info
name = "Kraken API OCEAN-USD price feed"
pair = 'OCEANUSD' # Choose the trading pair
interval = '1440' # Choose the time interval in minutes (1440 for daily)

from datetime import datetime, timedelta
end_datetime = datetime.now()
start_datetime = end_datetime - timedelta(days=7) # The previous week
since = int(start_datetime.timestamp() * 1000) # Choose the start time in Unix timestamp
url = f'https://api.kraken.com/0/public/OHLC?pair={pair}&interval={interval}&since={since}'

#create asset
(data_nft, datatoken, ddo) = ocean.assets.create_url_asset(name, url, {"from": alice})
print(f"Just published asset, with did={ddo.did}")
```

### 3. Alice creates a faucet for the asset

In the same Python console:
```python
datatoken.create_dispenser({"from": alice})
```

### 4. Bob gets a free datatoken, then consumes it

Now, you're Bob. First, download the file.

In the same Python console:
```python
# Set asset did. Practically, you'd get this from Ocean Market. _This_ example uses prior info.
ddo_did = ddo.did

# Bob gets a free datatoken, sends it to the service, and downloads
datatoken.dispense(to_wei(1), {"from": bob})
order_tx_id = ocean.assets.pay_for_access_service(ddo, {"from": bob}).hex()
asset_dir = ocean.assets.download_asset(ddo, bob, './', order_tx_id)

import os
file_name = os.path.join(asset_dir, 'file0')
```

Now, load the file and use its data.

The data follows the Kraken docs specs for Data, [here](https://docs.kraken.com/rest/#tag/Market-Data/operation/getOHLCData).

In the same Python console:
```python

# Load from file into memory
with open(file_name, "r") as file:
    # Data is a string with the result inside.
    data_str = file.read().rstrip().replace("'", '"')

import json
data = json.loads(data_str)

# Data is a list of lists
# -Outer dictionary contains 2 keys, one for errors and one for the result with the pair.
# -Inner dictionary have 9 entries each: Kline open time, Open price, High price, Low price, close Price, Vol, ..
# Get close price
close_prices = [float(data_at_day[4]) for data_at_day in data['result'][pair]]
print(f"close prices: {close_prices}")
```



================================================
FILE: READMEs/release-process.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

# The ocean.py Release Process

## Step 0: Update documentation

- If your changes affect what docs.oceanprotocol.com shows, then make changes in the docs repo https://github.com/oceanprotocol/docs and change

## Step 1: Bump version and push changes

- Identify the current version. It's listed at [pypi.org/project/ocean-lib](https://pypi.org/project/ocean-lib/), in this repo in [.bumpversion.cfg](../.bumpversion.cfg), and elsewhere.

- Create a new local feature branch, e.g. `git checkout -b feature/bumpversion-to-v1.2.5`

- Ensure you're in virtual env: `source venv/bin/activate`

- Run `./bumpversion.sh` to bump the project version, as follows:

  - To bump the major version (v**X**.Y.Z): `./bumpversion.sh major`
  - To bump the minor version (vX.**Y**.Z): `./bumpversion.sh minor`
  - To bump the patch version (vX.Y.**Z**): `./bumpversion.sh patch`
  - (Ocean.py follows [semantic versioning](https://semver.org/).)

- Commit the changes to the feature branch. For example:

  `git commit -m "Bump version v1.2.4 -> v1.2.5"`

- Push the feature branch to GitHub.

  `git push origin feature/bumpversion-to-v1.2.5`

## Step 2: Merge changes to main branch

- Make a pull request from the just-pushed branch.

- Wait for all the tests to pass!

- Merge the pull request into the `main` branch.

## Step 3: Release

- To make a GitHub release (which creates a Git tag):

  - Go to the ocean.py repo's Releases page <https://github.com/oceanprotocol/ocean.py/releases>
  - Click "Draft a new release".
  - For tag version, put something like `v1.2.5`
  - For release title, put the same value (like `v1.2.5`).
  - For the target, select the `main` branch, or the just-merged commit.
  - Describe the main changes. (In the future, these will come from the changelog.)
  - Click "Publish release".

## Step 4: Verify

- GitHub Actions will detect the release (a new tag) and run the deployment and publishing to PyPi.

- Check PyPI for the new release at <https://pypi.org/project/ocean-lib/>



================================================
FILE: READMEs/search-and-filter-assets.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->


# Quickstart: Search Assets Flow

This quickstart describes how assets can be found by their `tags` from Aquarius.


## 1. Setup

Ensure that you've already (a) [installed Ocean](install.md), and (b) [set up locally](setup-local.md) or [remotely](setup-remote.md).

## 2. Alice publishes datasets

Now, you're Alice.

```python
#data info
url = "https://raw.githubusercontent.com/trentmc/branin/main/branin.arff"

# Created a list of tags for the following assets
tags = [
    ["Branin dataset 1", "test", "ganache", "best asset"],
    ["Branin dataset 2", "test", "ocean"],
    ["Branin dataset 3", "AI", "dataset", "testing"],
]
# Publish few assets for testing
for tag in tags:
    name = tag[0]
    tx_dict = {"from": alice}
    metadata = ocean.assets.__class__.default_metadata(name, tx_dict)
    metadata.update({"tags": tag[1:]})
    (data_NFT, datatoken, ddo) = ocean.assets.create_url_asset(name, url, tx_dict, metadata=metadata)
    print(f"Just published asset, with did={ddo.did}")
```
## 3. Alice filters assets by their `tags`

Alice can filter the assets by a certain tag and after can retrieve the necessary
information afterwards.

```python
# Get a list of assets filtered by a given tag.
# All assets that contain the specified tag name
tag = "test"
all_ddos = ocean.assets.search(tag)

# Filter just by the `tags` key
filtered_ddos = list(
    filter(
        lambda a: tag in a.metadata["tags"],
        list(filter(lambda a: "tags" in a.metadata.keys(), all_ddos)),
    )
)

# Make sure that the provided tag is valid.
assert len(filtered_ddos) > 0, "Assets not found with this tag."

# Retrieve the wanted information from assets.
for ddo in filtered_ddos:
    print(f"ddo.did :{ddo.did}")
    print(f"ddo.metadata :{ddo.metadata}")
    print(f"ddo.nft :{ddo.nft}")
    print(f"ddo.datatokens :{ddo.datatokens}")
```

## Running custom queries
You can run any custom ES query using OceanAssets. For example:
```python
results = ocean.assets.query(
    {
        "query": {
            "query_string": {
                "query": "Branin dataset 1",
                "fields": ["metadata.name"],
            }
        }
    }
)
assert results[0].metadata["name"] == "Branin dataset 1"
```


================================================
FILE: READMEs/services.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

# About Ocean off-chain services

## Introduction

Ocean uses these off-chain services:

-   [Ocean Provider](https://github.com/oceanprotocol/provider) is for data services. Specifically, it's a REST API serving requests for two types of data services: static urls (for downloading data) and compute services. It's run by the marketplace or the data publisher.
-   [Ocean Aquarius](https://github.com/oceanprotocol/aquarius) is metadata cache REST API. This helps to aid search in marketplaces.

We now describe how to use these, for each of:

- Local Services: Default
- Local Services: Non-Default
- Remote Services: Default
- Remote Services: Non-Default

### Local Services: Default

When you follow [local setup](READMEs/setup-local.md), you will use Barge. Barge runs its own Ganache, and also its own Provider and Aquarius. You don't need to do more.

### Local Services: Non-Default

Instead of pointing to existing services (in Barge), you can run your own. Here's how.

Open a new console, and get provider running:

```console
docker run oceanprotocol/provider:latest
```

Open another new console, and get aquarius running:

```console
docker run oceanprotocol/aquarius:latest
```

Here are the urls for the local services, for use in the config dict.

-   Provider url: `http://127.0.0.1:8030`
-   Aquarius url: `http://127.0.0.1:5000`

Remember, here's how the config dict is set.
```python
from ocean_lib.example_config import get_config_dict
config = get_config_dict(<RPC_URL>) # returns a dict
# (then, here you can update the config dict as you wish)
ocean = Ocean(config)
```

### Remote Services: Default

For convenience, Ocean Protocol Foundation (OPF) runs an instance of Provider, and of Aquarius. [Ocean network docs](https://docs.oceanprotocol.com/core-concepts/networks) gives the urls.

When you follow [remote setup](READMEs/setup-remote.md), it will default to use these OPF-run Provider and Aquarius. You don't need to do more.


### Remote Services: Non-Default

You can run your own Provider or Aquarius, like shown above. And then point to it from your config dict.

You can also point to a Provider or Aquarius instance run by a 3rd party. Simply point to it from your config dict.


================================================
FILE: READMEs/setup-local.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

# Local Setup

Here, we do setup for local testing.

We assume you've already [installed Ocean](install.md).

## 1. Download barge and run services

Ocean `barge` runs ganache (local blockchain), Provider (data service), and Aquarius (metadata cache).

Barge helps you quickly become familiar with Ocean, because the local blockchain has low latency and no transaction fees. Accordingly, many READMEs use it. However, if you plan to only use Ocean with remote services, you don't need barge.

Note: if you are running MacOS or Windows, we recommend to go directly to [Remote Setup](setup-remote.md). Why: Barge uses Docker, which behaves badly on MacOS and Windows. We're working to address this [here](https://github.com/oceanprotocol/ocean.py/issues/1313).

In a new console:

```console
# Grab repo
git clone https://github.com/oceanprotocol/barge
cd barge

# Clean up old containers (to be sure)
docker system prune -a --volumes

# Run barge: start Ganache, Provider, Aquarius; deploy contracts; update ~/.ocean
# for support of type 2 transactions
export GANACHE_FORK=london
./start_ocean.sh
```

Now that we have barge running, we can mostly ignore its console while it runs.

## 2. Set envvars

From here on, go to a console different than Barge. (E.g. the console where you installed Ocean, or a new one.)

First, ensure that you're in the working directory, with venv activated:

```console
cd my_project
source venv/bin/activate
```

Then, set keys in readmes. As a Linux user, you'll use "`export`". In the same console:

```console
# keys for alice and bob in readmes
export TEST_PRIVATE_KEY1=0x8467415bb2ba7c91084d932276214b11a3dd9bdb2930fefa194b666dd8020b99
export TEST_PRIVATE_KEY2=0x1d751ded5a32226054cd2e71261039b65afb9ee1c746d055dd699b1150a5befc
export TEST_PRIVATE_KEY3=0x732fbb7c355aa8898f4cff92fa7a6a947339eaf026a08a51f171199e35a18ae0


# key for minting fake OCEAN
export FACTORY_DEPLOYER_PRIVATE_KEY=0xc594c6e5def4bab63ac29eed19a134c130388f74f019bc74b8f4389df2837a58
```

## 3. Setup in Python

In the same console, run Python console:
```console
python
```

In the Python console:
```python
# Create Ocean instance
from ocean_lib.example_config import get_config_dict
config = get_config_dict("http://localhost:8545")

from ocean_lib.ocean.ocean import Ocean
ocean = Ocean(config)

# Create OCEAN object. Barge auto-created OCEAN, and ocean instance knows
OCEAN = ocean.OCEAN_token

# Mint fake OCEAN to Alice & Bob
from ocean_lib.ocean.mint_fake_ocean import mint_fake_OCEAN
mint_fake_OCEAN(config)

# Create Alice's wallet
import os
from eth_account import Account

alice_private_key = os.getenv("TEST_PRIVATE_KEY1")
alice = Account.from_key(private_key=alice_private_key)
assert ocean.wallet_balance(alice) > 0, "Alice needs ETH"
assert OCEAN.balanceOf(alice) > 0, "Alice needs OCEAN"

# Create additional wallets. While some flows just use Alice wallet, it's simpler to do all here.
bob_private_key = os.getenv('TEST_PRIVATE_KEY2')
bob = Account.from_key(private_key=bob_private_key)
assert ocean.wallet_balance(bob) > 0, "Bob needs ETH"
assert OCEAN.balanceOf(bob) > 0, "Bob needs OCEAN"

carlos_private_key = os.getenv('TEST_PRIVATE_KEY3')
carlos = Account.from_key(private_key=carlos_private_key)
assert ocean.wallet_balance(carlos) > 0, "Carlos needs ETH"
assert OCEAN.balanceOf(carlos) > 0, "Carlos needs OCEAN"


# Compact wei <> eth conversion
from ocean_lib.ocean.util import to_wei, from_wei
```

## 4. Next step

You've now set up everything you need for local testing, congrats!

The next step - the fun one - is to walk through the [main flow](main-flow.md). In it, you'll publish a data asset, post for free / for sale, dispense it / buy it, and consume it.

Because you've set up for local, you'll be doing all these steps on the local network.


================================================
FILE: READMEs/setup-remote.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

# Remote Setup

Here, we do setup for Mumbai, the testnet for Polygon. It's similar for other remote chains.

We assume you've already [installed Ocean](install.md).

Here, we will:
1. Configure networks
2. Create two accounts - `REMOTE_TEST_PRIVATE_KEY1` and `2`
3. Get fake MATIC on Mumbai
4. Get fake OCEAN on Mumbai
5. Set envvars
6. Set up Alice and Bob wallets in Python

Let's go!

## 1. Configure Networks

### 1.1 Setup network RPC URLs for all desired networks

All [Ocean chain deployments](https://docs.oceanprotocol.com/discover/networks) (Eth mainnet, Polygon, etc) are supported.

## 2. Create EVM Accounts (One-Time)

An EVM account is singularly defined by its private key. Its address is a function of that key. Let's generate two accounts!

In a new or existing console, run Python.
```console
python
```

In the Python console:

```python
from eth_account.account import Account
account1 = Account.create()
account2 = Account.create()

print(f"""
REMOTE_TEST_PRIVATE_KEY1={account1.key.hex()}, ADDRESS1={account1.address}
REMOTE_TEST_PRIVATE_KEY2={account2.key.hex()}, ADDRESS2={account2.address}
""")
```

Then, hit Ctrl-C to exit the Python console.

Now, you have two EVM accounts (address & private key). Save them somewhere safe, like a local file or a password manager.

These accounts will work on any EVM-based chain: production chains like Eth mainnet and Polygon, and testnets like Goerli and Mumbai. Here, we'll use them for Mumbai.


## 3. Get (fake) MATIC on Mumbai

We need the a network's native token to pay for transactions on the network. [ETH](https://ethereum.org/en/get-eth/) is the native token for Ethereum mainnet; [MATIC](https://polygon.technology/matic-token/) is the native token for Polygon, and [(fake) MATIC](https://faucet.polygon.technology/) is the native token for Mumbai.

To get free (fake) MATIC on Mumbai:
1. Go to the faucet https://faucet.polygon.technology/. Ensure you've selected "Mumbai" network and "MATIC" token.
2. Request funds for ADDRESS1
3. Request funds for ADDRESS2

You can confirm receiving funds by going to the following url, and seeing your reported MATIC balance: `https://mumbai.polygonscan.com/address/<ADDRESS1 or ADDRESS2>`

## 4. Get (fake) OCEAN on Mumbai

[OCEAN](https://oceanprotocol.com/token) can be used as a data payment token, and locked into veOCEAN for Data Farming / curation. The READMEs show how to use OCEAN in both cases.
- OCEAN is an ERC20 token with a finite supply, rooted in Ethereum mainnet at address [`0x967da4048cD07aB37855c090aAF366e4ce1b9F48`](https://etherscan.io/token/0x967da4048cD07aB37855c090aAF366e4ce1b9F48).
- OCEAN on other production chains derives from the Ethereum mainnet OCEAN. OCEAN on Polygon (mOCEAN) is at [`0x282d8efce846a88b159800bd4130ad77443fa1a1`](https://polygonscan.com/token/0x282d8efce846a88b159800bd4130ad77443fa1a1).
- (Fake) OCEAN is on each testnet. Fake OCEAN on Mumbai is at [`0xd8992Ed72C445c35Cb4A2be468568Ed1079357c8`](https://mumbai.polygonscan.com/token/0xd8992Ed72C445c35Cb4A2be468568Ed1079357c8).

To get free (fake) OCEAN on Mumbai:
1. Go to the faucet https://faucet.mumbai.oceanprotocol.com/
2. Request funds for ADDRESS1
3. Request funds for ADDRESS2

You can confirm receiving funds by going to the following url, and seeing your reported OCEAN balance: `https://mumbai.polygonscan.com/token/0xd8992Ed72C445c35Cb4A2be468568Ed1079357c8?a=<ADDRESS1 or ADDRESS2>`

## 5. Set envvars

As usual, Linux/MacOS needs "`export`" and Windows needs "`set`". In the console:

#### Linux & MacOS users:
```console
# For accounts: set private keys
export REMOTE_TEST_PRIVATE_KEY1=<your REMOTE_TEST_PRIVATE_KEY1>
export REMOTE_TEST_PRIVATE_KEY2=<your REMOTE_TEST_PRIVATE_KEY2>

export MUMBAI_RPC_URL=<your RPC_URL> # exported used for convenience/security, you can also use the direct URL string later
```


#### Windows users:
```console
# For accounts: set private keys
set REMOTE_TEST_PRIVATE_KEY1=<your REMOTE_TEST_PRIVATE_KEY1>
set REMOTE_TEST_PRIVATE_KEY2=<your REMOTE_TEST_PRIVATE_KEY2>

set MUMBAI_RPC_URL=<your RPC_URL> # exported used for convenience/security, you can also use the direct URL string later
```

Optionally, chainlist.org has other RPCs for [Mumbai](https://chainlist.org/chain/80001) and [Polygon](https://chainlist.org/chain/137).

## 6. Setup in Python

In your working console, run Python:
```console
python
```

In the Python console:
```python
# Create Ocean instance
import os
from ocean_lib.example_config import get_config_dict
from ocean_lib.ocean.ocean import Ocean
config = get_config_dict(os.getenv("MUMBAI_RPC_URL"))  # you can also input the string directly
ocean = Ocean(config)

# Create OCEAN object. ocean_lib knows where OCEAN is on all remote networks
OCEAN = ocean.OCEAN_token

# Create Alice's wallet
from eth_account import Account

alice_private_key = os.getenv('REMOTE_TEST_PRIVATE_KEY1')
alice = Account.from_key(private_key=alice_private_key)
assert ocean.wallet_balance(alice) > 0, "Alice needs MATIC"
assert OCEAN.balanceOf(alice) > 0, "Alice needs OCEAN"

# Create Bob's wallet. While some flows just use Alice wallet, it's simpler to do all here.
bob_private_key = os.getenv('REMOTE_TEST_PRIVATE_KEY2')
bob = Account.from_key(private_key=bob_private_key)
assert ocean.wallet_balance(bob) > 0, "Bob needs MATIC"
assert OCEAN.balanceOf(bob) > 0, "Bob needs OCEAN"

# Compact wei <> eth conversion
from ocean_lib.ocean.util import to_wei, from_wei
```

If you get a gas-related error like `transaction underpriced`, you'll need to change the `priority_fee` or `max_fee`.

## Next step

You've now set up everything you need for testing on a remote chain, congrats! it's similar for any remote chain.

The next step is to walk through the [main flow](main-flow.md). In it, you'll publish a data asset, post for free / for sale, dispense it / buy it, and consume it.

Because you've set up for remote, you'll be doing all these steps on the remote network.


================================================
FILE: READMEs/using-clef.md
================================================
<!--
Copyright 2023 Ocean Protocol Foundation
SPDX-License-Identifier: Apache-2.0
-->

# Using hardware wallets with ocean.py

This README describes how to setup ocean.py with hardware wallets.

We assume you've already (a) [installed Ocean](install.md), configured any environment variables necessary and created the Ocean object as described in (b) done [local setup](setup-local.md) or [remote setup](setup-remote.md).
These instructions are applicable to both local and remote setup. If you intend to use hardware wallets ONLY, then you can skip the wallet creation parts in the setup instructions.

## 1. Setting up and running Clef
ocean.py allows the use of hardware wallets via [Clef](https://geth.ethereum.org/docs/clef/tutorial), an account management tool included within [Geth](https://geth.ethereum.org/)

To use a hardware wallet with ocean.py, start by [installing Geth](https://geth.ethereum.org/docs/install-and-build/installing-geth).
Once finished, type the following command in a bash console and follow the on-screen prompts to set of Clef:

```console
clef init
```

If you need to create a new account, you can use the command `clef newaccount`. For other usefull commands, please consult the [Clef documentation](https://geth.ethereum.org/docs/tools/clef/introduction).

Once Clef is configured, run it in a bash console as needed, i.e.

```console
# you can use a different chain if needed
clef --chainid 8996
```

You can also customise your run, e.g. `clef --chainid 8996 --advanced`.

Keep the clef console open, you will be required to approve transactions and input your password when so requested.

## 2. Connect ocean.py to Clef via Brownie

In your Python console where you have setup the Ocean object:

```python
from ocean_lib.web3_internal.clef import get_clef_accounts
clef_accounts = get_clef_accounts()
```

Approve the connection from the Clef console. This will add your Clef account to the `accounts` array.
You can now use the Clef account instead of any wallet argument, e.g. when publishing or consuming DDOs.


```python
# pick up the account for convenience
clef_account = clef_accounts[index]

# make sure account is funded. Let's transfer some ether and OCEAN from alice
from ocean_lib.ocean.util import send_ether
send_ether(config, alice, clef_account.address, to_wei(4))
OCEAN.transfer(clef_account, to_wei(4), {"from": alice})

# publish and download an asset
name = "Branin dataset"
url = "https://raw.githubusercontent.com/trentmc/branin/main/branin.arff"

(data_nft, datatoken, ddo) = ocean.assets.create_url_asset(name, url, {"from": clef_account})
datatoken.mint(clef_account, to_wei(1), {"from": clef_account})
order_tx_id = ocean.assets.pay_for_access_service(ddo, {"from": clef_account})
ocean.assets.download_asset(ddo, clef_account, './', order_tx_id)

```

Please note that you need to consult your clef console periodically to approve transactions and input your password if needed.
You can use the ClefAccount object seamlessly, in any transaction, just like regular Accounts. Simply send your transaction with `{"from": clef_account}` where needed.


================================================
FILE: bumpversion.sh
================================================
#!/bin/bash
##
## Copyright 2023 Ocean Protocol Foundation
## SPDX-License-Identifier: Apache-2.0
##

set -x
set -e

usage(){
  echo "Usage: $0 {major|minor|patch} [--tag]"
  exit 1
}

if ! [ -x "$(command -v bumpversion)" ]; then
  echo 'Error: bumpversion is not installed.' >&2
  exit 1
elif ! git diff-index --quiet HEAD -- >/dev/null 2>&1; then
  echo 'There are local changes in your the git repository. Please commit or stash them before bumping version.' >&2
  exit 1
fi

if [ "$#" -lt 1 ]; then
    echo "Illegal number of parameters"
    usage
elif [[ $1 != 'major' && $1 != 'minor' && $1 != 'patch' ]]; then
    echo 'First argument must be {major|minor|patch}'
    usage
fi

if [[ $2 == '--tag' ]]; then
  if git branch --contains $(git rev-parse --verify HEAD) | grep -E 'main'; then
    eval "bumpversion --tag --commit $1"
  else
    echo "Only main tags can be tagged"
    exit 1
  fi
else
  eval "bumpversion --no-tag $1"
fi



================================================
FILE: conftest.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#

# This is the global conftest. EVERY SINGLE TEST looks at this
# - For tests that use ganache, import conftest_ganache.py. Just don't put it here.
# - For tests that use remote networks, do your own thing. Just don't put it here.


================================================
FILE: conftest_ganache.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#
from typing import Tuple

import pytest

from ocean_lib.example_config import get_config_dict
from ocean_lib.models.data_nft import DataNFT
from ocean_lib.models.data_nft_factory import DataNFTFactoryContract
from ocean_lib.models.datatoken1 import Datatoken1
from ocean_lib.models.factory_router import FactoryRouter
from ocean_lib.models.fixed_rate_exchange import FixedRateExchange
from ocean_lib.ocean.util import get_address_of_type, send_ether, to_wei
from ocean_lib.web3_internal.contract_utils import get_contracts_addresses_all_networks
from tests.resources.helper_functions import (
    deploy_erc721_erc20,
    get_another_consumer_wallet,
    get_consumer_ocean_instance,
    get_consumer_wallet,
    get_factory_deployer_wallet,
    get_file1,
    get_file2,
    get_file3,
    get_ganache_wallet,
    get_provider_wallet,
    get_publisher_ocean_instance,
    get_publisher_wallet,
    get_wallet,
    setup_logging,
)

_NETWORK = "ganache"

setup_logging()


@pytest.fixture(autouse=True)
def setup_all(request, config, ocean_token):
    # a test can skip setup_all() via decorator "@pytest.mark.nosetup_all"
    if "nosetup_all" in request.keywords:
        return

    wallet = get_ganache_wallet()

    if not wallet:
        return

    if not get_contracts_addresses_all_networks(config):
        print("Can not find adddresses.")
        return

    balance = config["web3_instance"].eth.get_balance(wallet.address)
    assert balance >= to_wei(10), "Need more ETH"

    amt_distribute = to_wei(1000)
    ocean_token.mint(wallet, to_wei(2000), {"from": wallet})

    for w in (get_publisher_wallet(), get_consumer_wallet()):
        balance = config["web3_instance"].eth.get_balance(w.address)

        if balance < to_wei(2):
            send_ether(config, wallet, w.address, to_wei(4))

        if ocean_token.balanceOf(w) < to_wei(100):
            ocean_token.mint(w, amt_distribute, {"from": wallet})


@pytest.fixture
def config():
    return get_config_dict()


@pytest.fixture
def publisher_ocean():
    return get_publisher_ocean_instance()


@pytest.fixture
def basic_asset(publisher_ocean, publisher_wallet):
    name = "Branin dataset"
    url = "https://raw.githubusercontent.com/trentmc/branin/main/branin.arff"

    (data_nft, datatoken, ddo) = publisher_ocean.assets.create_url_asset(
        name, url, {"from": publisher_wallet}
    )

    assert ddo.nft["name"] == name
    assert len(ddo.datatokens) == 1

    return (data_nft, datatoken, ddo)


@pytest.fixture
def consumer_ocean():
    return get_consumer_ocean_instance()


@pytest.fixture
def publisher_wallet():
    return get_publisher_wallet()


@pytest.fixture
def consumer_wallet():
    return get_consumer_wallet()


@pytest.fixture
def another_consumer_wallet():
    return get_another_consumer_wallet()


@pytest.fixture
def factory_deployer_wallet(config):
    return get_factory_deployer_wallet(config)


@pytest.fixture
def ocean_address(config) -> str:
    return get_address_of_type(config, "Ocean")


@pytest.fixture
def ocean_token(config, ocean_address) -> Datatoken1:
    return Datatoken1(config, ocean_address)


@pytest.fixture
def factory_router(config):
    return FactoryRouter(config, get_address_of_type(config, "Router"))


@pytest.fixture
def data_nft_factory(config):
    return DataNFTFactoryContract(config, get_address_of_type(config, "ERC721Factory"))


@pytest.fixture
def provider_wallet():
    return get_provider_wallet()


@pytest.fixture
def file1():
    return get_file1()


@pytest.fixture
def file2():
    return get_file2()


@pytest.fixture
def file3():
    return get_file3()


@pytest.fixture
def FRE(config) -> FixedRateExchange:
    return FixedRateExchange(config, get_address_of_type(config, "FixedPrice"))


@pytest.fixture
def data_nft(config, publisher_wallet) -> DataNFT:
    return deploy_erc721_erc20(config, publisher_wallet)


@pytest.fixture
def data_NFT_and_DT(config, publisher_wallet) -> Tuple[DataNFT, Datatoken1]:
    return deploy_erc721_erc20(config, publisher_wallet, publisher_wallet)


@pytest.fixture
def DT(data_NFT_and_DT) -> Datatoken1:
    (_, DT) = data_NFT_and_DT
    return DT


# aliases
@pytest.fixture
def OCEAN(ocean_token) -> Datatoken1:
    return ocean_token


@pytest.fixture
def alice(publisher_wallet):
    return publisher_wallet


@pytest.fixture
def bob(consumer_wallet):
    return consumer_wallet


@pytest.fixture
def carlos():
    return get_wallet(8)


@pytest.fixture
def dan():
    return get_wallet(7)


================================================
FILE: ocean_lib/__init__.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#

"""Initialises ocean lib package."""

__author__ = """OceanProtocol"""
# fmt: off
__version__ = '3.1.2'
# fmt: on


================================================
FILE: ocean_lib/agreements/__init__.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#


================================================
FILE: ocean_lib/agreements/consumable.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#
from enforce_typing import enforce_types


class ConsumableCodes:
    """
    Contains constant values for:
     - OK
     - ASSET_DISABLED
     - CONNECTIVITY_FAIL
     - CREDENTIAL_NOT_IN_ALLOW_LIST
     - CREDENTIAL_IN_DENY_LIST
    """

    OK = 0
    ASSET_DISABLED = 1
    CONNECTIVITY_FAIL = 2
    CREDENTIAL_NOT_IN_ALLOW_LIST = 3
    CREDENTIAL_IN_DENY_LIST = 4
    ASSET_UNLISTED = 5


class MalformedCredential(Exception):
    pass


class AssetNotConsumable(Exception):
    @enforce_types
    def __init__(self, consumable_code: int) -> None:
        self.consumable_code = consumable_code


================================================
FILE: ocean_lib/agreements/service_types.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#
"""Agreements module."""


class ServiceTypes:
    """Types of Service allowed in ocean protocol DDO services for V4."""

    ASSET_ACCESS = "access"
    CLOUD_COMPUTE = "compute"
    AUTHORIZATION = "wss"


class ServiceTypesNames:
    DEFAULT_ACCESS_NAME = "Download service"
    DEFAULT_COMPUTE_NAME = "Compute service"


================================================
FILE: ocean_lib/aquarius/__init__.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#
"""Ocean Aquarius module."""
from .aquarius import Aquarius  # noqa


================================================
FILE: ocean_lib/aquarius/aquarius.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#
"""
Aquarius module.
Help to communicate with the metadata store.
"""

import json
import logging
import time
from typing import Optional, Tuple, Union

from enforce_typing import enforce_types

from ocean_lib.assets.ddo import DDO
from ocean_lib.http_requests.requests_session import get_requests_session

logger = logging.getLogger("aquarius")


class Aquarius:
    """Aquarius wrapper to call different endpoint of aquarius component."""

    @enforce_types
    def __init__(self, aquarius_url: str) -> None:
        """
        This class wraps Aquarius REST API.

        :param aquarius_url: Url of the aquarius instance.
        """
        assert aquarius_url, f'Invalid url "{aquarius_url}"'
        # :HACK:
        if "/api/aquarius/assets" in aquarius_url:
            aquarius_url = aquarius_url[: aquarius_url.find("/api/aquarius/assets")]

        self.requests_session = get_requests_session()
        try:
            response = self.requests_session.get(f"{aquarius_url}")
        except Exception:
            response = None

        if not response or response.status_code != 200:
            raise Exception(f"Invalid or unresponsive aquarius url {aquarius_url}")

        self.base_url = f"{aquarius_url}/api/aquarius/assets"

        logging.debug(f"Aquarius connected at {aquarius_url}")
        logging.debug(f"Aquarius API documentation at {aquarius_url}/api/v1/docs")
        logging.debug(f"Metadata assets (DDOs) at {self.base_url}")

    @classmethod
    def get_instance(cls, metadata_cache_uri: str) -> "Aquarius":
        return cls(metadata_cache_uri)

    @enforce_types
    def get_ddo(self, did: str) -> Optional[DDO]:
        """Retrieve ddo for a given did."""
        response = self.requests_session.get(f"{self.base_url}/ddo/{did}")

        if response.status_code == 200:
            response_dict = response.json()

            return DDO.from_dict(response_dict)

        return None

    @enforce_types
    def ddo_exists(self, did: str) -> bool:
        """Is this DDO in Aqua?"""
        response = self.requests_session.get(f"{self.base_url}/ddo/{did}").content
        return f"Asset DID {did} not found in Elasticsearch" not in str(response)

    @enforce_types
    def get_ddo_metadata(self, did: str) -> dict:
        """Returns a given DDO's "metadata" field values"""
        response = self.requests_session.get(f"{self.base_url}/metadata/{did}")
        if response.status_code == 200:
            return response.json()

        return {}

    @enforce_types
    def query_search(self, search_query: dict) -> list:
        """
        Search using a query.

        Currently implemented is the MongoDB query model to search for documents according to:
        https://docs.mongodb.com/manual/tutorial/query-documents/

        And an Elastic Search driver, which implements a basic parser to convert the query into
        elastic search format.

        Example: query_search({"price":[0,10]})

        :param search_query: Python dictionary, query following elasticsearch syntax
        :return: List of DDO
        """
        response = self.requests_session.post(
            f"{self.base_url}/query",
            data=json.dumps(search_query),
            headers={"content-type": "application/json"},
        )

        if response.status_code == 200:
            return response.json()["hits"]["hits"]

        raise ValueError(f"Unable to search for DDO: {response.content}")

    @enforce_types
    def validate_ddo(self, ddo: DDO) -> Tuple[bool, Union[list, dict]]:
        """Does the DDO conform to the Ocean DDO schema?
        Schema definition: https://docs.oceanprotocol.com/core-concepts/did-ddo
        """
        ddo_dict = ddo.as_dictionary()
        data = json.dumps(ddo_dict, separators=(",", ":")).encode("utf-8")

        response = self.requests_session.post(
            f"{self.base_url.replace('/v1/', '/')}/ddo/validate",
            data=data,
            headers={"content-type": "application/octet-stream"},
        )

        parsed_response = response.json()

        if parsed_response.get("hash"):
            return True, parsed_response

        return False, parsed_response

    @enforce_types
    def wait_for_ddo(self, did: str, timeout=60):
        start = time.time()
        ddo = None
        while not ddo:
            ddo = self.get_ddo(did)

            if not ddo:
                time.sleep(0.2)

            if time.time() - start > timeout:
                break

        return ddo

    @enforce_types
    def wait_for_ddo_update(self, ddo: DDO, tx: str):
        start = time.time()
        ddo2 = None
        while True:
            try:
                ddo2 = self.get_ddo(ddo.did)
            except ValueError:
                pass
            if not ddo2:
                time.sleep(0.2)
            elif ddo2.event.get("tx") == tx:
                logger.debug(
                    f"Transaction matching the given tx id detected in metadata store. ddo2.event = {ddo2.event}"
                )
                break

            elapsed_time = time.time() - start
            if elapsed_time > 60:
                break

        return ddo2


================================================
FILE: ocean_lib/aquarius/test/__init__.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#


================================================
FILE: ocean_lib/aquarius/test/conftest.py
================================================
from conftest_ganache import *


================================================
FILE: ocean_lib/aquarius/test/test_aquarius.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#
import pytest

from ocean_lib.aquarius.aquarius import Aquarius
from ocean_lib.assets.ddo import DDO
from ocean_lib.example_config import METADATA_CACHE_URI


@pytest.mark.unit
def test_init():
    """Tests initialisation of Aquarius objects."""
    aqua = Aquarius("http://172.15.0.5:5000/api/aquarius/assets")
    assert aqua.base_url == "http://172.15.0.5:5000/api/aquarius/assets"


@pytest.mark.integration
def test_aqua_functions_for_single_ddo(publisher_ocean, publisher_wallet, basic_asset):
    """Tests against single-ddo functions of Aquarius."""
    aquarius = publisher_ocean.assets._aquarius

    _, _, ddo1 = basic_asset
    metadata1 = ddo1.metadata

    ddo2 = aquarius.wait_for_ddo(ddo1.did)
    assert ddo2.metadata == ddo1.metadata

    ddo3 = publisher_ocean.assets.resolve(ddo1.did)
    assert ddo3.did == ddo1.did, "Aquarius could not resolve the did."
    assert ddo3.did == ddo2.did, "Aquarius could not resolve the did."

    aqua_uri = publisher_ocean.config_dict.get("METADATA_CACHE_URI")
    ddo4 = Aquarius.get_instance(aqua_uri).get_ddo(ddo2.did)
    assert isinstance(ddo4, DDO)
    assert ddo4.did == ddo2.did, "Aquarius could not resolve the did."

    metadata2 = aquarius.get_ddo_metadata(ddo2.did)
    assert metadata2 == metadata1


@pytest.mark.unit
def test_invalid_search_query():
    """Tests query search with an invalid query."""
    aquarius = Aquarius.get_instance(METADATA_CACHE_URI)
    search_query = "not_a_dict"
    with pytest.raises(TypeError):
        aquarius.query_search(search_query=search_query)


@pytest.mark.unit
def test_empty_responses():
    aquarius = Aquarius.get_instance(METADATA_CACHE_URI)
    assert aquarius.get_ddo_metadata("inexistent_ddo") == {}


================================================
FILE: ocean_lib/assets/__init__.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#


================================================
FILE: ocean_lib/assets/asset_downloader.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#

import logging
import os
from typing import Optional, Union

from enforce_typing import enforce_types

from ocean_lib.agreements.consumable import AssetNotConsumable, ConsumableCodes
from ocean_lib.assets.ddo import DDO
from ocean_lib.data_provider.data_service_provider import DataServiceProvider
from ocean_lib.services.service import Service

logger = logging.getLogger(__name__)


@enforce_types
def download_asset_files(
    ddo: DDO,
    service: Service,
    consumer_wallet,
    destination: str,
    order_tx_id: Union[str, bytes],
    index: Optional[int] = None,
    userdata: Optional[dict] = None,
) -> str:
    """Download asset data file or result file from compute job.

    :param ddo: DDO instance
    :param service: Sevice instance
    :param consumer_wallet: Wallet instance of the consumer
    :param destination: Path, str
    :param order_tx_id: hex str or hex bytes the transaction hash of the startOrder tx
    :param index: Index of the document that is going to be downloaded, Optional[int]
    :param userdata: Dict of additional data from user
    :return: asset folder path, str
    """
    data_provider = DataServiceProvider

    if not service.service_endpoint:
        logger.error(
            'Consume asset failed, service definition is missing the "serviceEndpoint".'
        )
        raise AssertionError(
            'Consume asset failed, service definition is missing the "serviceEndpoint".'
        )

    if index is not None:
        assert isinstance(index, int), logger.error("index has to be an integer.")
        assert index >= 0, logger.error("index has to be 0 or a positive integer.")

    consumable_result = is_consumable(
        ddo,
        service,
        {"type": "address", "value": consumer_wallet.address},
        with_connectivity_check=True,
        userdata=userdata,
    )
    if consumable_result != ConsumableCodes.OK:
        raise AssetNotConsumable(consumable_result)

    service_index_in_asset = ddo.get_index_of_service(service)
    asset_folder = os.path.join(
        destination, f"datafile.{ddo.did},{service_index_in_asset}"
    )

    if not os.path.exists(asset_folder):
        os.makedirs(asset_folder)

    data_provider.download(
        did=ddo.did,
        service=service,
        tx_id=order_tx_id,
        consumer_wallet=consumer_wallet,
        destination_folder=asset_folder,
        index=index,
        userdata=userdata,
    )

    return asset_folder


@enforce_types
def is_consumable(
    ddo: DDO,
    service: Service,
    credential: Optional[dict] = None,
    with_connectivity_check: bool = True,
    userdata: Optional[dict] = None,
) -> bool:
    """Checks whether an asset is consumable and returns a ConsumableCode."""
    if ddo.is_disabled:
        return ConsumableCodes.ASSET_DISABLED

    if with_connectivity_check and not DataServiceProvider.check_asset_file_info(
        ddo.did, service.id, service.service_endpoint, userdata=userdata
    ):
        return ConsumableCodes.CONNECTIVITY_FAIL

    # to be parameterized in the future, can implement other credential classes
    if ddo.requires_address_credential:
        return ddo.validate_access(credential)

    return ConsumableCodes.OK


================================================
FILE: ocean_lib/assets/credentials.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#
from typing import Optional

from enforce_typing import enforce_types

from ocean_lib.agreements.consumable import ConsumableCodes, MalformedCredential


class AddressCredentialMixin:
    @enforce_types
    def get_addresses_of_class(self, access_class: str = "allow") -> list:
        """Get a filtered list of addresses from credentials (use with allow/deny)."""
        address_entry = self.get_address_entry_of_class(access_class)
        if not address_entry:
            return []

        if "values" not in address_entry:
            raise MalformedCredential("No values key in the address credential.")

        return [addr.lower() for addr in address_entry["values"]]

    @enforce_types
    def requires_credential(self) -> bool:
        """Checks whether the ddo requires an address credential."""
        allowed_addresses = self.get_addresses_of_class("allow")
        denied_addresses = self.get_addresses_of_class("deny")

        return bool(allowed_addresses or denied_addresses)

    @enforce_types
    def validate_access(self, credential: Optional[dict] = None) -> int:
        """Checks a credential dictionary against the address allow/deny lists."""
        address = simplify_credential_to_address(credential)

        allowed_addresses = self.get_addresses_of_class("allow")
        denied_addresses = self.get_addresses_of_class("deny")

        if not address and not self.requires_credential():
            return ConsumableCodes.OK

        if allowed_addresses and address.lower() not in allowed_addresses:
            return ConsumableCodes.CREDENTIAL_NOT_IN_ALLOW_LIST

        if not allowed_addresses and address.lower() in denied_addresses:
            return ConsumableCodes.CREDENTIAL_IN_DENY_LIST

        return ConsumableCodes.OK

    @enforce_types
    def add_address_to_access_class(
        self, address: str, access_class: str = "allow"
    ) -> None:
        """Adds an address to an address list (either allow or deny)."""
        address = address.lower()

        if not self.credentials or access_class not in self.credentials:
            self.credentials[access_class] = [{"type": "address", "values": [address]}]
            return

        address_entry = self.get_address_entry_of_class(access_class)

        if not address_entry:
            self.credentials[access_class].append(
                {"type": "address", "values": [address]}
            )
            return

        lc_addresses = self.get_addresses_of_class(access_class)

        if address not in lc_addresses:
            lc_addresses.append(address)

        address_entry["values"] = lc_addresses

    @enforce_types
    def remove_address_from_access_class(
        self, address: str, access_class: str = "allow"
    ) -> None:
        """Removes an address from an address list (either allow or deny)i."""
        address = address.lower()

        if not self.credentials or access_class not in self.credentials:
            return

        address_entry = self.get_address_entry_of_class(access_class)

        if not address_entry:
            return

        lc_addresses = self.get_addresses_of_class(access_class)

        if address not in lc_addresses:
            return

        lc_addresses.remove(address)
        address_entry["values"] = lc_addresses

    @enforce_types
    def get_address_entry_of_class(self, access_class: str = "allow") -> Optional[dict]:
        """Get address credentials entry of the specified access class. access_class = "allow" or "deny"."""
        entries = self.credentials.get(access_class, [])
        address_entries = [entry for entry in entries if entry.get("type") == "address"]
        return address_entries[0] if address_entries else None


@enforce_types
def simplify_credential_to_address(credential: Optional[dict]) -> Optional[str]:
    """Extracts address value from credential dictionary."""
    if not credential:
        return None

    if not credential.get("value"):
        raise MalformedCredential("Received empty address.")

    return credential["value"]


================================================
FILE: ocean_lib/assets/ddo.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#
import copy
import logging
from typing import Optional

from enforce_typing import enforce_types

from ocean_lib.assets.credentials import AddressCredentialMixin
from ocean_lib.data_provider.fileinfo_provider import FileInfoProvider
from ocean_lib.ocean.util import create_checksum
from ocean_lib.services.service import Service

logger = logging.getLogger("ddo")


class DDO(AddressCredentialMixin):
    """Create, import, export, validate DDO objects."""

    @enforce_types
    def __init__(
        self,
        did: Optional[str] = None,
        context: Optional[list] = None,
        chain_id: Optional[int] = None,
        nft_address: Optional[str] = None,
        metadata: Optional[dict] = None,
        services: Optional[list] = None,
        credentials: Optional[dict] = None,
        nft: Optional[dict] = None,
        datatokens: Optional[list] = None,
        event: Optional[dict] = None,
        stats: Optional[dict] = None,
    ) -> None:
        self.did = did
        self.context = context or ["https://w3id.org/did/v1"]
        self.chain_id = chain_id
        self.nft_address = nft_address
        self.metadata = metadata
        self.version = "4.1.0"
        self.services = services or []
        self.credentials = credentials or {}
        self.nft = nft
        self.datatokens = datatokens
        self.event = event
        self.stats = stats

    @property
    @enforce_types
    def requires_address_credential(self) -> bool:
        """Checks if an address credential is required on this ddo."""
        return self.requires_credential()

    @property
    @enforce_types
    def allowed_addresses(self) -> list:
        """Lists addresses that are explicitly allowed in credentials."""
        return self.get_addresses_of_class("allow")

    @property
    @enforce_types
    def denied_addresses(self) -> list:
        """Lists addresses that are explicitly denied in credentials."""
        return self.get_addresses_of_class("deny")

    @enforce_types
    def add_address_to_allow_list(self, address: str) -> None:
        """Adds an address to allowed addresses list."""
        self.add_address_to_access_class(address, "allow")

    @enforce_types
    def add_address_to_deny_list(self, address: str) -> None:
        """Adds an address to the denied addresses list."""
        self.add_address_to_access_class(address, "deny")

    @enforce_types
    def remove_address_from_allow_list(self, address: str) -> None:
        """Removes address from allow list (if it exists)."""
        self.remove_address_from_access_class(address, "allow")

    @enforce_types
    def remove_address_from_deny_list(self, address: str) -> None:
        """Removes address from deny list (if it exists)."""
        self.remove_address_from_access_class(address, "deny")

    @classmethod
    @enforce_types
    def from_dict(cls, dictionary: dict) -> "DDO":
        """Import a JSON dict into this DDO."""
        values = copy.deepcopy(dictionary)

        services = (
            []
            if "services" not in values
            else [Service.from_dict(value) for value in values.pop("services")]
        )

        args = [
            values.pop("id", None),
            values.pop("@context", None),
            values.pop("chainId", None),
            values.pop("nftAddress", None),
            values.pop("metadata", None),
            services,
            values.pop("credentials", None),
            values.pop("nft", None),
            values.pop("datatokens", None),
            values.pop("event", None),
            values.pop("stats", None),
        ]

        if args[0] is None:
            return UnavailableDDO(*args)

        return cls(*args)

    @enforce_types
    def as_dictionary(self) -> dict:
        """
        Return the DDO as a JSON dict.

        :return: dict
        """

        data = {
            "@context": self.context,
            "id": self.did,
            "version": self.version,
            "chainId": self.chain_id,
        }

        data["nftAddress"] = self.nft_address

        services = [value.as_dictionary() for value in self.services]
        args = ["metadata", "credentials", "nft", "datatokens", "event", "stats"]
        attrs = list(
            filter(
                lambda attr: not not attr[1],
                map(lambda attr: (attr, getattr(self, attr, None)), args),
            )
        )
        attrs.append(("services", services))
        data.update(attrs)
        return data

    @enforce_types
    def add_service(self, service: Service) -> None:
        """
        Add a service to the list of services on the V4 DDO.

        :param service: To add service, Service
        """
        service.encrypt_files(self.nft_address, self.chain_id)

        logger.debug(
            f"Adding service with service type {service.type} with did {self.did}"
        )
        self.services.append(service)

    @enforce_types
    def create_compute_service(
        self,
        service_id: str,
        service_endpoint: str,
        datatoken_address: str,
        files,
        compute_values: Optional[dict] = None,
        timeout: Optional[int] = 3600,
    ) -> None:
        if not compute_values:
            compute_values = {
                "allowRawAlgorithm": False,
                "allowNetworkAccess": True,
                "publisherTrustedAlgorithms": [],
                "publisherTrustedAlgorithmPublishers": [],
            }

        compute_service = Service(
            service_id=service_id,
            service_type="compute",
            service_endpoint=service_endpoint,
            datatoken=datatoken_address,
            files=files,
            timeout=timeout,
            compute_values=compute_values,
        )

        self.add_service(compute_service)

    @enforce_types
    def get_service_by_id(self, service_id: str) -> Service:
        """Return Service with the given id.
        Return None if service with the given id not found."""
        return next(
            (service for service in self.services if service.id == service_id), None
        )

    @enforce_types
    def get_service_by_index(self, service_index: int) -> Service:
        """Return Service with the given index.
        Return None if service with the given index not found."""
        return (
            self.services[service_index] if service_index < len(self.services) else None
        )

    @enforce_types
    def get_index_of_service(self, service: Service) -> int:
        """Return index of the given Service.
        Return None if service was not found."""
        return next(
            (
                index
                for index, this_service in enumerate(self.services)
                if this_service.id == service.id
            ),
            None,
        )

    @enforce_types
    def generate_trusted_algorithms(self) -> dict:
        """Returns a trustedAlgorithm dictionary for service at index 0."""
        resp = FileInfoProvider.fileinfo(
            self.did, self.get_service_by_index(0), with_checksum=True
        )
        files_checksum = [resp_item["checksum"] for resp_item in resp.json()]
        container = self.metadata["algorithm"]["container"]
        return {
            "did": self.did,
            "filesChecksum": "".join(files_checksum),
            "containerSectionChecksum": create_checksum(
                container["entrypoint"] + container["checksum"]
            ),
        }

    @property
    def is_disabled(self) -> bool:
        return not self.metadata or (self.nft and self.nft["state"] not in [0, 5])


class UnavailableDDO(DDO):
    pass


================================================
FILE: ocean_lib/assets/test/__init__.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#


================================================
FILE: ocean_lib/assets/test/conftest.py
================================================
from conftest_ganache import *


================================================
FILE: ocean_lib/assets/test/test_asset_downloader.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#
import os
from unittest.mock import patch

import pytest
from requests.exceptions import InvalidURL

from ocean_lib.agreements.consumable import AssetNotConsumable, ConsumableCodes
from ocean_lib.agreements.service_types import ServiceTypes
from ocean_lib.assets.asset_downloader import download_asset_files, is_consumable
from ocean_lib.assets.ddo import DDO
from ocean_lib.data_provider.data_service_provider import DataServiceProvider
from ocean_lib.models.datatoken_base import TokenFeeInfo
from ocean_lib.ocean.util import to_wei
from ocean_lib.services.service import Service
from tests.resources.ddo_helpers import get_first_service_by_type, get_sample_ddo


@pytest.mark.unit
def test_is_consumable():
    ddo_dict = get_sample_ddo()
    ddo = DDO.from_dict(ddo_dict)
    service_dict = ddo_dict["services"][0]
    service = Service.from_dict(service_dict)
    with patch(
        "ocean_lib.assets.test.test_asset_downloader.DataServiceProvider.check_asset_file_info",
        return_value=False,
    ):
        assert (
            is_consumable(ddo, service, {}, True) == ConsumableCodes.CONNECTIVITY_FAIL
        )

    with patch(
        "ocean_lib.assets.test.test_asset_downloader.DataServiceProvider.check_asset_file_info",
        return_value=True,
    ):
        assert (
            is_consumable(ddo, service, {"type": "address", "value": "0xdddd"}, True)
            == ConsumableCodes.CREDENTIAL_NOT_IN_ALLOW_LIST
        )


@pytest.mark.unit
def test_ocean_assets_download_failure(publisher_wallet):
    """Tests that downloading from an empty service raises an AssertionError."""

    ddo_dict = get_sample_ddo()
    ddo = DDO.from_dict(ddo_dict)
    access_service = get_first_service_by_type(ddo, ServiceTypes.ASSET_ACCESS)
    access_service.service_endpoint = None
    ddo.services[0] = access_service

    with pytest.raises(AssertionError):
        download_asset_files(
            ddo,
            access_service,
            publisher_wallet,
            "test_destination",
            "test_order_tx_id",
        )


@pytest.mark.unit
def test_invalid_provider_uri(publisher_wallet):
    """Tests with invalid provider URI that raise AssertionError."""
    ddo_dict = get_sample_ddo()
    ddo = DDO.from_dict(ddo_dict)
    ddo.services[0].service_endpoint = "http://nothing-here.com"

    with pytest.raises(InvalidURL):
        download_asset_files(
            ddo,
            ddo.services[0],
            publisher_wallet,
            "test_destination",
            "test_order_tx_id",
        )


@pytest.mark.unit
def test_invalid_state(publisher_wallet):
    """Tests different scenarios that raise AssetNotConsumable."""
    ddo_dict = get_sample_ddo()
    ddo = DDO.from_dict(ddo_dict)
    ddo.nft["state"] = 1

    with pytest.raises(AssetNotConsumable):
        download_asset_files(
            ddo,
            ddo.services[0],
            publisher_wallet,
            "test_destination",
            "test_order_tx_id",
        )

    ddo.metadata = []
    with pytest.raises(AssetNotConsumable):
        download_asset_files(
            ddo,
            ddo.services[0],
            publisher_wallet,
            "test_destination",
            "test_order_tx_id",
        )


@pytest.mark.integration
def test_ocean_assets_download_indexes(publisher_wallet):
    """Tests different values of indexes that raise AssertionError."""

    ddo_dict = get_sample_ddo()
    ddo = DDO.from_dict(ddo_dict)

    index = range(3)
    with pytest.raises(TypeError):
        download_asset_files(
            ddo,
            ddo.services[0],
            publisher_wallet,
            "test_destination",
            "test_order_tx_id",
            index=index,
        )

    index = -1
    with pytest.raises(AssertionError):
        download_asset_files(
            ddo,
            ddo.services[0],
            publisher_wallet,
            "test_destination",
            "test_order_tx_id",
            index=index,
        )


@pytest.mark.integration
def test_ocean_assets_download_destination_file(
    tmpdir,
    publisher_ocean,
    publisher_wallet,
    basic_asset,
):
    """Convert tmpdir: py._path.local.LocalPath to str, satisfy enforce-typing."""
    data_provider = DataServiceProvider
    data_nft, datatoken, ddo = basic_asset
    access_service = get_first_service_by_type(ddo, ServiceTypes.ASSET_ACCESS)

    datatoken.mint(
        publisher_wallet.address,
        to_wei(50),
        {"from": publisher_wallet},
    )

    initialize_response = data_provider.initialize(
        did=ddo.did,
        service=access_service,
        consumer_address=publisher_wallet.address,
    )

    provider_fees = initialize_response.json()["providerFee"]
    consume_market_fees = TokenFeeInfo(
        address=publisher_wallet.address,
        token=datatoken.address,
    )

    receipt = datatoken.start_order(
        consumer=publisher_wallet.address,
        service_index=ddo.get_index_of_service(access_service),
        provider_fees=provider_fees,
        consume_market_fees=consume_market_fees,
        tx_dict={"from": publisher_wallet},
    )

    orders = publisher_ocean.get_user_orders(
        publisher_wallet.address, datatoken.address
    )
    assert datatoken.address in [order.address for order in orders]
    assert receipt.transactionHash.hex() in [
        order.transactionHash.hex() for order in orders
    ]

    written_path = download_asset_files(
        ddo,
        access_service,
        publisher_wallet,
        str(tmpdir),
        receipt.transactionHash.hex(),
    )

    assert os.path.exists(written_path)

    # index not found, even though tx_id exists
    with pytest.raises(AssertionError):
        download_asset_files(
            ddo,
            ddo.services[0],
            publisher_wallet,
            str(tmpdir),
            receipt.transactionHash.hex(),
            index=4,
        )


================================================
FILE: ocean_lib/assets/test/test_ddo.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#
import pytest

from ocean_lib.agreements.consumable import MalformedCredential
from ocean_lib.assets.credentials import simplify_credential_to_address
from ocean_lib.assets.ddo import DDO
from ocean_lib.services.service import Service
from tests.resources.ddo_helpers import (
    get_key_from_v4_sample_ddo,
    get_sample_ddo,
    get_sample_ddo_with_compute_service,
)


@pytest.mark.unit
def test_ddo_utils():
    """Tests the structure of a JSON format of the V4 DDO."""
    ddo_dict = get_sample_ddo()
    assert isinstance(ddo_dict, dict)

    assert isinstance(ddo_dict, dict)
    assert ddo_dict["@context"] == ["https://w3id.org/did/v1"]
    context = ddo_dict["@context"]
    assert (
        ddo_dict["id"]
        == "did:op:d32696f71f3318c92bcf325e2e51e6e8299c0eb6d362ddcfa77d2a3e0c1237b5"
    )
    did = ddo_dict["id"]
    assert ddo_dict["version"] == "4.1.0"
    assert ddo_dict["chainId"] == 8996
    chain_id = ddo_dict["chainId"]

    assert ddo_dict["metadata"] == {
        "created": "2020-11-15T12:27:48Z",
        "updated": "2021-05-17T21:58:02Z",
        "description": "Sample description",
        "name": "Sample asset",
        "type": "dataset",
        "author": "OPF",
        "license": "https://market.oceanprotocol.com/terms",
    }
    metadata = ddo_dict["metadata"]
    assert isinstance(ddo_dict["services"], list)
    assert ddo_dict["services"] == [
        {
            "id": "1",
            "type": "access",
            "files": "0x0000",
            "name": "Download service",
            "description": "Download service",
            "datatokenAddress": "0x123",
            "serviceEndpoint": "http://172.15.0.4:8030",
            "timeout": 0,
        }
    ]

    services = [
        Service.from_dict(value)
        for value in ddo_dict["services"]
        if isinstance(value, dict)
    ]

    assert ddo_dict["credentials"] == {
        "allow": [{"type": "address", "values": ["0x123", "0x456"]}],
        "deny": [{"type": "address", "values": ["0x2222", "0x333"]}],
    }
    credentials = ddo_dict["credentials"]

    assert ddo_dict["nft"] == {
        "address": "0xCc708430E6a174BD4639A979F578A2176A0FA3fA",
        "name": "Ocean Protocol Asset v4",
        "symbol": "OCEAN-A-v4",
        "owner": "0x0000000",
        "state": 0,
        "created": "2000-10-31T01:30:00",
    }
    nft = ddo_dict["nft"]

    assert ddo_dict["datatokens"] == [
        {
            "address": "0x000000",
            "name": "Datatoken 1",
            "symbol": "DT-1",
            "serviceId": "1",
        }
    ]
    datatokens = ddo_dict["datatokens"]

    assert ddo_dict["event"] == {
        "tx": "0x8d127de58509be5dfac600792ad24cc9164921571d168bff2f123c7f1cb4b11c",
        "block": 12831214,
        "from": "0xAcca11dbeD4F863Bb3bC2336D3CE5BAC52aa1f83",
        "contract": "0x1a4b70d8c9DcA47cD6D0Fb3c52BB8634CA1C0Fdf",
        "datetime": "2000-10-31T01:30:00",
    }
    event = ddo_dict["event"]

    # Sample ddo
    assert ddo_dict["stats"] == {"consumes": 4}
    stats = ddo_dict["stats"]

    ddo = DDO(
        did=did,
        context=context,
        chain_id=chain_id,
        metadata=metadata,
        services=services,
        credentials=credentials,
        nft=nft,
        nft_address="0xCc708430E6a174BD4639A979F578A2176A0FA3fA",
        datatokens=datatokens,
        event=event,
        stats=stats,
    )
    ddo_dict_v2 = ddo.as_dictionary()

    ddo_v2 = DDO.from_dict(ddo_dict_v2)
    assert ddo_v2.as_dictionary() == ddo_dict


@pytest.mark.unit
def test_add_service():
    """Tests adding a compute service."""

    ddo_dict = get_sample_ddo()
    ddo = DDO.from_dict(ddo_dict)

    compute_values = {
        "namespace": "ocean-compute",
        "cpus": 2,
        "gpus": 4,
        "gpuType": "NVIDIA Tesla V100 GPU",
        "memory": "128M",
        "volumeSize": "2G",
        "allowRawAlgorithm": False,
        "allowNetworkAccess": True,
        "publisherTrustedAlgorithmPublishers": ["0x234", "0x235"],
        "publisherTrustedAlgorithms": [
            {
                "did": "did:op:123",
                "filesChecksum": "100",
                "containerSectionChecksum": "200",
            },
            {
                "did": "did:op:124",
                "filesChecksum": "110",
                "containerSectionChecksum": "210",
            },
        ],
    }
    ddo.create_compute_service(
        service_id="2",
        service_endpoint="http://172.15.0.4:8030",
        datatoken_address="0x124",
        files="0x0001",
        compute_values=compute_values,
    )
    assert len(ddo.as_dictionary()["services"]) > 1

    expected_access_service = get_key_from_v4_sample_ddo(
        key="services", file_name="ddo_v4_with_compute_service.json"
    )[0]
    assert ddo.as_dictionary()["services"][0] == expected_access_service

    expected_compute_service = get_key_from_v4_sample_ddo(
        key="services", file_name="ddo_v4_with_compute_service.json"
    )[1]

    assert ddo.as_dictionary()["services"][1]["id"] == expected_compute_service["id"]

    assert (
        ddo.as_dictionary()["services"][1]["name"] == expected_compute_service["name"]
    )
    assert (
        ddo.as_dictionary()["services"][1]["description"]
        == expected_compute_service["description"]
    )
    assert (
        ddo.as_dictionary()["services"][1]["serviceEndpoint"]
        == expected_compute_service["serviceEndpoint"]
    )
    assert (
        ddo.as_dictionary()["services"][1]["datatokenAddress"]
        == expected_compute_service["datatokenAddress"]
    )
    assert (
        ddo.as_dictionary()["services"][1]["files"] == expected_compute_service["files"]
    )
    assert (
        ddo.as_dictionary()["services"][1]["timeout"]
        == expected_compute_service["timeout"]
    )
    assert (
        ddo.as_dictionary()["services"][1]["compute"]
        == expected_compute_service["compute"]
    )


@pytest.mark.unit
def test_get_service_by_id():
    """Tests retrieving services from the V4 DDO."""
    ddo_dict = get_sample_ddo_with_compute_service()
    ddo = DDO.from_dict(ddo_dict)
    expected_access_service = get_key_from_v4_sample_ddo(
        key="services", file_name="ddo_v4_with_compute_service.json"
    )[0]

    assert ddo.get_service_by_id("1").as_dictionary() == expected_access_service

    expected_compute_service = get_key_from_v4_sample_ddo(
        key="services", file_name="ddo_v4_with_compute_service.json"
    )[1]
    assert ddo.get_service_by_id("2").as_dictionary() == expected_compute_service


@pytest.mark.unit
def test_credentials():
    ddo_dict = get_sample_ddo_with_compute_service()
    ddo = DDO.from_dict(ddo_dict)
    assert ddo.requires_address_credential
    assert ddo.allowed_addresses == ["0x123", "0x456"]
    assert ddo.denied_addresses == ["0x2222", "0x333"]

    ddo.add_address_to_allow_list("0xaAA")
    assert "0xaaa" in ddo.allowed_addresses
    ddo.remove_address_from_allow_list("0xaAA")
    assert "0xaaa" not in ddo.allowed_addresses
    ddo.remove_address_from_allow_list("0xaAA")

    ddo.add_address_to_deny_list("0xaAA")
    assert "0xaaa" in ddo.denied_addresses
    ddo.remove_address_from_deny_list("0xaAA")
    assert "0xaaa" not in ddo.denied_addresses

    assert ddo.validate_access({"type": "address", "value": "0x123"}) == 0
    # not allowed
    assert ddo.validate_access({"type": "address", "value": "0x444"}) == 3

    ddo_dict = get_sample_ddo_with_compute_service()
    del ddo_dict["credentials"]["allow"]
    ddo = DDO.from_dict(ddo_dict)
    assert ddo.validate_access({"type": "address", "value": "0x444"}) == 0
    # specifically denied
    assert ddo.validate_access({"type": "address", "value": "0x333"}) == 4

    ddo_dict = get_sample_ddo_with_compute_service()
    del ddo_dict["credentials"]["allow"][0]["values"]
    ddo = DDO.from_dict(ddo_dict)
    with pytest.raises(
        MalformedCredential, match="No values key in the address credential"
    ):
        ddo.get_addresses_of_class("allow")

    ddo_dict = get_sample_ddo_with_compute_service()
    del ddo_dict["credentials"]
    ddo = DDO.from_dict(ddo_dict)
    ddo.remove_address_from_allow_list("0xAA")
    ddo.add_address_to_allow_list("0xAA")

    ddo_dict = get_sample_ddo_with_compute_service()
    ddo_dict["credentials"]["allow"] = []
    ddo = DDO.from_dict(ddo_dict)
    ddo.remove_address_from_allow_list("0xAA")
    ddo.add_address_to_allow_list("0xAA")


@pytest.mark.unit
def test_credential_simplification():
    assert simplify_credential_to_address(None) is None
    with pytest.raises(MalformedCredential, match="Received empty address."):
        simplify_credential_to_address({"malformed": "no value"})
    assert (
        simplify_credential_to_address({"type": "address", "value": "0x11"}) == "0x11"
    )


@pytest.mark.unit
def test_is_disabled():
    ddo_dict = get_sample_ddo()

    for state in range(6):
        ddo_dict["nft"]["state"] = state
        ddo = DDO.from_dict(ddo_dict)

        # adhere to https://docs.oceanprotocol.com/core-concepts/did-ddo#state
        if state in [0, 5]:
            assert not ddo.is_disabled
        else:
            assert ddo.is_disabled


================================================
FILE: ocean_lib/data_provider/__init__.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#


================================================
FILE: ocean_lib/data_provider/base.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#

"""Provider module."""
import logging
import os
import re
from json import JSONDecodeError
from math import ceil
from typing import Dict, List, Optional, Tuple, Union
from unittest.mock import Mock

import requests
from enforce_typing import enforce_types
from requests.exceptions import InvalidURL
from requests.models import PreparedRequest, Response
from requests.sessions import Session

from ocean_lib.exceptions import DataProviderException
from ocean_lib.http_requests.requests_session import get_requests_session
from ocean_lib.web3_internal.clef import ClefAccount
from ocean_lib.web3_internal.utils import sign_with_clef, sign_with_key

logger = logging.getLogger(__name__)


class DataServiceProviderBase:
    """DataServiceProviderBase class."""

    _http_client = get_requests_session()
    provider_info = None

    @staticmethod
    @enforce_types
    def get_http_client() -> Session:
        """Get the http client."""
        return DataServiceProviderBase._http_client

    @staticmethod
    @enforce_types
    def set_http_client(http_client: Session) -> None:
        """Set the http client to something other than the default `requests`."""
        DataServiceProviderBase._http_client = http_client

    @staticmethod
    @enforce_types
    def sign_message(wallet, msg: str, provider_uri: str) -> Tuple[str, str]:
        method, nonce_endpoint = DataServiceProviderBase.build_endpoint(
            "nonce", provider_uri
        )

        nonce_response = DataServiceProviderBase._http_method(
            method, url=nonce_endpoint, params={"userAddress": wallet.address}
        )

        if (
            not nonce_response
            or not hasattr(nonce_response, "status_code")
            or nonce_response.status_code != 200
            or "nonce" not in nonce_response.json()
        ):
            current_nonce = 0
        else:
            current_nonce = int(ceil(float(nonce_response.json()["nonce"])))

        nonce = current_nonce + 1

        print(f"signing message with nonce {nonce}: {msg}, account={wallet.address}")

        if isinstance(wallet, ClefAccount):
            return nonce, str(sign_with_clef(f"{msg}{nonce}", wallet))

        return nonce, str(sign_with_key(f"{msg}{nonce}", wallet._private_key.hex()))

    @staticmethod
    @enforce_types
    def get_url(config_dict: dict) -> str:
        """
        Return the DataProvider component url.

        :return: Url, str
        """
        return _remove_slash(config_dict.get("PROVIDER_URL"))

    @staticmethod
    @enforce_types
    def get_service_endpoints(provider_uri: str) -> Dict[str, List[str]]:
        """
        Return the service endpoints from the provider URL.
        """
        provider_info = DataServiceProviderBase._http_method(
            "get", url=provider_uri
        ).json()

        return provider_info["serviceEndpoints"]

    @staticmethod
    @enforce_types
    def get_c2d_environments(provider_uri: str, chain_id: int) -> Optional[str]:
        """
        Return the provider address
        """
        try:
            method, envs_endpoint = DataServiceProviderBase.build_endpoint(
                "computeEnvironments", provider_uri, {"chainId": chain_id}
            )
            environments = DataServiceProviderBase._http_method(
                method, url=envs_endpoint
            ).json()

            if str(chain_id) not in environments:
                logger.warning(
                    "You might be using an older provider. ocean.py can not verify the chain id."
                )
                return environments

            return environments[str(chain_id)]
        except (requests.exceptions.RequestException, KeyError):
            pass

        return []

    @staticmethod
    @enforce_types
    def get_provider_address(provider_uri: str, chain_id: int) -> Optional[str]:
        """
        Return the provider address
        """
        try:
            provider_info = DataServiceProviderBase._http_method(
                "get", provider_uri
            ).json()

            if "providerAddress" in provider_info:
                logger.warning(
                    "You might be using an older provider. ocean.py can not verify the chain id."
                )
                return provider_info["providerAddress"]

            return provider_info["providerAddresses"][str(chain_id)]
        except requests.exceptions.RequestException:
            pass

        return None

    @staticmethod
    @enforce_types
    def get_root_uri(service_endpoint: str) -> str:
        provider_uri = service_endpoint

        if "/api" in provider_uri:
            i = provider_uri.find("/api")
            provider_uri = provider_uri[:i]

        parts = provider_uri.split("/")

        if len(parts) < 2:
            raise InvalidURL(f"InvalidURL {service_endpoint}.")

        if parts[-2] == "services":
            provider_uri = "/".join(parts[:-2])

        result = _remove_slash(provider_uri)

        if not result:
            raise InvalidURL(f"InvalidURL {service_endpoint}.")

        try:
            root_result = "/".join(parts[0:3])
            response = requests.get(root_result).json()
        except (requests.exceptions.RequestException, JSONDecodeError):
            raise InvalidURL(f"InvalidURL {service_endpoint}.")

        if "providerAddresses" not in response:
            if "providerAddress" in response:
                logger.warning(
                    "You might be using an older provider. ocean.py can not verify the chain id."
                )
            else:
                raise InvalidURL(
                    f"Invalid Provider URL {service_endpoint}, no providerAddresses."
                )

        return result

    @staticmethod
    @enforce_types
    def is_valid_provider(provider_uri: str) -> bool:
        try:
            DataServiceProviderBase.get_root_uri(provider_uri)
        except InvalidURL:
            return False

        return True

    @staticmethod
    @enforce_types
    def build_endpoint(
        service_name: str, provider_uri: str, params: Optional[dict] = None
    ) -> Tuple[str, str]:
        provider_uri = DataServiceProviderBase.get_root_uri(provider_uri)
        service_endpoints = DataServiceProviderBase.get_service_endpoints(provider_uri)

        method, url = service_endpoints[service_name]
        url = urljoin(provider_uri, url)

        if params:
            req = PreparedRequest()
            req.prepare_url(url, params)
            url = req.url

        return method, url

    @staticmethod
    @enforce_types
    def write_file(
        response: Response,
        destination_folder: Union[str, bytes, os.PathLike],
        index: int,
    ) -> None:
        """
        Write the response content in a file in the destination folder.
        :param response: Response
        :param destination_folder: Destination folder, string
        :param index: file index
        :return: None
        """
        if response.status_code != 200:
            logger.warning(f"consume failed: {response.reason}")
            return

        with open(os.path.join(destination_folder, f"file{index}"), "wb") as f:
            for chunk in response.iter_content(chunk_size=4096):
                f.write(chunk)
        logger.info(f"Saved downloaded file in {f.name}")

    @staticmethod
    @enforce_types
    def _validate_content_disposition(header: str) -> bool:
        pattern = re.compile(r"\\|\.\.|/")
        return not bool(pattern.findall(header))

    @staticmethod
    @enforce_types
    def _get_file_name(response: Response) -> Optional[str]:
        try:
            if not DataServiceProviderBase._validate_content_disposition(
                response.headers.get("content-disposition")
            ):
                logger.error(
                    "Invalid content disposition format. It was not possible to get the file name."
                )
                return None

            return re.match(
                r"attachment;filename=(.+)",
                response.headers.get("content-disposition"),
            )[1]
        except Exception as e:
            logger.warning(f"It was not possible to get the file name. {e}")
            return None

    @staticmethod
    @enforce_types
    def _http_method(method: str, *args, **kwargs) -> Optional[Union[Mock, Response]]:
        try:
            return getattr(DataServiceProviderBase._http_client, method.lower())(
                *args, **kwargs
            )
        except Exception:
            logger.error(
                f"Error invoking http method {method}: args={str(args)}, kwargs={str(kwargs)}"
            )
            raise

    @staticmethod
    @enforce_types
    def check_response(
        response,
        endpoint_name: str,
        endpoint: str,
        payload: Union[Dict, bytes],
        success_codes: Optional[List] = None,
        exception_type=DataProviderException,
    ):
        if not response or not hasattr(response, "status_code"):
            if isinstance(response, Response) and response.status_code == 400:
                error = response.json().get(
                    "error", response.json().get("errors", "unknown error")
                )

                raise DataProviderException(f"{endpoint_name} failed: {error}")

            response_content = getattr(response, "content", "<none>")

            raise DataProviderException(
                f"Failed to get a response for request: {endpoint_name}={endpoint}, payload={payload}, response is {response_content}"
            )

        if not success_codes:
            success_codes = [200]

        if response.status_code not in success_codes:
            msg = (
                f"request failed at the {endpoint_name}"
                f"{endpoint}, reason {response.text}, status {response.status_code}"
            )
            logger.error(msg)
            raise exception_type(msg)

        return None


@enforce_types
def urljoin(*args) -> str:
    trailing_slash = "/" if args[-1].endswith("/") else ""

    return "/".join(map(lambda x: str(x).strip("/"), args)) + trailing_slash


def _remove_slash(path: str) -> str:
    path = path[:-1] if path.endswith("/") else path
    path = path[1:] if path.startswith("/") else path

    return path


================================================
FILE: ocean_lib/data_provider/data_encryptor.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#

"""Provider module."""
import json
import logging
from typing import Union

from enforce_typing import enforce_types
from requests.models import Response

from ocean_lib.data_provider.base import DataServiceProviderBase
from ocean_lib.exceptions import OceanEncryptAssetUrlsError

logger = logging.getLogger(__name__)


class DataEncryptor(DataServiceProviderBase):
    """DataEncryptor class."""

    @staticmethod
    @enforce_types
    def encrypt(
        objects_to_encrypt: Union[list, str, bytes, dict],
        provider_uri: str,
        chain_id: int,
    ) -> Response:
        if isinstance(objects_to_encrypt, dict):
            data = json.dumps(objects_to_encrypt, separators=(",", ":"))
            payload = data.encode("utf-8")
        elif isinstance(objects_to_encrypt, str):
            payload = objects_to_encrypt.encode("utf-8")
        else:
            payload = objects_to_encrypt

        method, encrypt_endpoint = DataServiceProviderBase.build_endpoint(
            "encrypt", provider_uri, {"chainId": chain_id}
        )

        response = DataServiceProviderBase._http_method(
            method,
            encrypt_endpoint,
            data=payload,
            headers={"Content-type": "application/octet-stream"},
        )

        DataServiceProviderBase.check_response(
            response,
            "encryptEndpoint",
            encrypt_endpoint,
            payload,
            [201],
            OceanEncryptAssetUrlsError,
        )

        logger.info(
            f"Asset urls encrypted successfully, encrypted urls str: {response.text},"
            f" encryptedEndpoint {encrypt_endpoint}"
        )

        return response


================================================
FILE: ocean_lib/data_provider/data_service_provider.py
================================================
#
# Copyright 2023 Ocean Protocol Foundation
# SPDX-License-Identifier: Apache-2.0
#

"""Provider module."""
import json
import logging
from json import JSONDecodeError
from pathlib import Path
from typing import Any, Dict, List, Optional, Union

from enforce_typing import enforce_types
from requests.models import PreparedRequest, Response

from ocean_lib.agreements.service_types import ServiceTypes
from ocean_lib.data_provider.base import DataServiceProviderBase
from ocean_lib.data_provider.fileinfo_provider import FileInfoProvider
from ocean_lib.http_requests.requests_session import get_requests_session
from ocean_lib.models.compute_input import ComputeInput
from ocean_lib.structures.algorithm_metadata import AlgorithmMetadata

logger = logging.getLogger(__name__)


class DataServiceProvider(DataServiceProviderBase):
    """DataServiceProvider class.

    The main functions available are:
    - consume_service
    - run_compute_service (not implemented yet)
    """

    _http_client = get_requests_session()
    provider_info = None

    @staticmethod
    @enforce_types
    def initialize(
        did: str,
        service: Any,  # Can not add Service typing due to enforce_type errors.
        consumer_address: str,
        userdata: Optional[Dict] = None,
    ) -> Response:
        method, initialize_endpoint = DataServiceProvider.build_endpoint(
            "initialize", service.service_endpoint
        )

        payload = {
            "documentId": did,
            "serviceId": service.id,
            "consumerAddress": consumer_address,
        }

        if userdata is not None:
            userdata = json.dumps(userdata)
            payload["userdata"] = userdata

        response = DataServiceProvider._http_method(
            method, url=initialize_endpoint, params=payload
        )

        DataServiceProviderBase.check_response(
            response, "initializeEndpoint", initialize_endpoint, payload
        )

        logger.info(
            f"Service initialized successfully"
            f" initializeEndpoint {initialize_endpoint}"
        )

        return response

    @staticmethod
    @enforce_types
    def initialize_compute(
        datasets: List[Dict[str, Any]],
        algorithm_data: Dict[str, Any],
        service_endpoint,
        consumer_address: str,
        compute_environment: str,
        valid_until: int,
    ) -> Response:
        """This function initializes compute services.

        To determine the Provider instance that will be called, we rely on the first dataset.
        The first dataset is also required to have a compute service.
        """
        (
            method,
            initialize_compute_endpoint,
        ) = DataServiceProvider.build_endpoint("initializeCompute", service_endpoint)

        payload = {
            "datasets": datasets,
            "algorithm": algorithm_data,
            "compute": {
                "env": compute_environment,
                "validUntil": valid_until,
            },
            "consumerAddress": consumer_address,
        }

        response = DataServiceProvider._http_method(
            method,
            initialize_compute_endpoint,
            data=json.dumps(payload),
            headers={"content-type": "application/json"},
        )

        DataServiceProviderBase.check_response(
            response, "initializeComputeEndpoint", initialize_compute_endpoint, payload
        )

        logger.info(
            f"Service initialized successfully"
            f" initializeComputeEndpoint {initialize_compute_endpoint}"
        )

        return response

    @staticmethod
    @enforce_types
    def download(
        did: str,
        service: Any,  # Can not add Service typing due to enforce_type errors.
        tx_id: Union[str, bytes],
        consumer_wallet,
        destination_folder: Union[str, Path],
        index: Optional[int] = None,
        userdata: Optional[Dict] = None,
    ) -> None:
        service_endpoint = service.service_endpoint
        fileinfo_response = FileInfoProvider.fileinfo(did, service, userdata=userdata)

        files = fileinfo_response.json()
        indexes = range(len(files))
        if index is not None:
            assert isinstance(index, int), logger.error("index has to be an integer.")
            assert index >= 0, logger.error("index has to be 0 or a positive integer.")
            assert index < len(files), logger.error(
                "index can not be bigger than the number of files"
            )
            indexes = [index]

        method, download_endpoint = DataServiceProvider.build_endpoint(
            "download", service_endpoint
        )

        payload = {
            "documentId": did,
            "serviceId": service.id,
            "consumerAddress": consumer_wallet.address,
            "transferTxId": tx_id,
        }

        if userdata:
            userdata = json.dumps(userdata)
            payload["userdata"] = userdata

        for i in indexes:
            payload["fileIndex"] = i
            payload["nonce"], payload["signature"] = DataServiceProvider.sign_message(
                consumer_wallet, did, provider_uri=service_endpoint
            )
            response = DataServiceProvider._http_method(
                method, url=download_endpoint, params=payload, stream=True, timeout=3
            )

            DataServiceProviderBase.check_response(
                response, "downloadEndpoint", download_endpoint, payload
            )

            DataServiceProvider.write_file(response, destination_folder, i)

            logger.info(
                f"DDO downloaded successfully" f" downloadEndpoint {download_endpoint}"
            )

    @staticmethod
    # @enforce_types omitted due to subscripted generics error
    def start_compute_job(
        dataset_compute_service: Any,  # Can not add Service typing due to enforce_type errors.
        consumer,
        dataset: ComputeInput,
        compute_environment: str,
        algorithm: Optional[ComputeInput] = None,
        algorithm_meta: Optional[AlgorithmMetadata] = None,
        algorithm_custom_data: Optional[str] = None,
        input_datasets: Optional[List[ComputeInput]] = None,
    ) -> Dict[str, Any]:
        """
        Start a compute job.

        Either algorithm or algorithm_meta must be defined.

        :param dataset_compute_service:
        :param consumer: hex str the ethereum address of the consumer executing the compute job
        :param dataset: ComputeInput dataset with a compute service
        :param compute_environment: str compute environment id
        :param algorithm: ComputeInput algorithm witha download service.
        :param algorithm_meta: AlgorithmMetadata algorithm metadata
        :param algorithm_custom_data: dict customizable algo parameters (ie. no of iterations, etc)
        :param input_datasets: List[ComputeInput] additional input datasets
        :return job_info dict
        """
        assert (
            algorithm or algorithm_meta
        ), "either an algorithm did or an algorithm meta must be provided."

        assert (
            hasattr(dataset_compute_service, "type")
            and dataset_compute_service.type == ServiceTypes.CLOUD_COMPUTE
        ), "invalid compute service"

        payload = DataServiceProvider._prepare_compute_payload(
            consumer=consumer,
            dataset=dataset,
            compute_environment=compute_environment,
            dataset_compute_service=dataset_compute_service,
            algorithm=algorithm,
            algorithm_meta=algorithm_meta,
            algorithm_custom_data=algorithm_custom_data,
            input_datasets=input_datasets,
        )
        logger.info(f"invoke start compute endpoint with this url: {payload}")
        method, compute_endpoint = DataServiceProvider.build_endpoint(
            "computeStart", dataset_compute_service.service_endpoint
        )
        response = DataServiceProvider._http_method(
            method,
            compute_endpoint,
            data=json.dumps(payload),
            headers={"content-type": "application/json"},
        )

        logger.debug(
            f"got DataProvider execute response: {response.content} with status-c
Download .txt
gitextract_72imfimc/

├── .bumpversion.cfg
├── .codeclimate.yml
├── .copyright.tmpl
├── .coveragerc
├── .docignore
├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── black.yml
│       ├── build.yml
│       ├── libcheck.yml
│       ├── pytest.yml
│       └── release.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .prospector.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── READMEs/
│   ├── c2d-flow-more-examples.md
│   ├── c2d-flow.md
│   ├── custody-light-flow.md
│   ├── developers.md
│   ├── df.md
│   ├── gas-strategy-remote.md
│   ├── install.md
│   ├── key-value-private.md
│   ├── key-value-public.md
│   ├── main-flow.md
│   ├── parameters.md
│   ├── predict-eth.md
│   ├── profile-nfts-flow.md
│   ├── publish-flow-credentials.md
│   ├── publish-flow-graphql.md
│   ├── publish-flow-onchain.md
│   ├── publish-flow-restapi.md
│   ├── release-process.md
│   ├── search-and-filter-assets.md
│   ├── services.md
│   ├── setup-local.md
│   ├── setup-remote.md
│   └── using-clef.md
├── bumpversion.sh
├── conftest.py
├── conftest_ganache.py
├── ocean_lib/
│   ├── __init__.py
│   ├── agreements/
│   │   ├── __init__.py
│   │   ├── consumable.py
│   │   └── service_types.py
│   ├── aquarius/
│   │   ├── __init__.py
│   │   ├── aquarius.py
│   │   └── test/
│   │       ├── __init__.py
│   │       ├── conftest.py
│   │       └── test_aquarius.py
│   ├── assets/
│   │   ├── __init__.py
│   │   ├── asset_downloader.py
│   │   ├── credentials.py
│   │   ├── ddo.py
│   │   └── test/
│   │       ├── __init__.py
│   │       ├── conftest.py
│   │       ├── test_asset_downloader.py
│   │       └── test_ddo.py
│   ├── data_provider/
│   │   ├── __init__.py
│   │   ├── base.py
│   │   ├── data_encryptor.py
│   │   ├── data_service_provider.py
│   │   ├── fileinfo_provider.py
│   │   └── test/
│   │       ├── __init__.py
│   │       ├── conftest.py
│   │       ├── test_base.py
│   │       └── test_data_service_provider.py
│   ├── example_config.py
│   ├── exceptions.py
│   ├── http_requests/
│   │   ├── __init__.py
│   │   └── requests_session.py
│   ├── models/
│   │   ├── __init__.py
│   │   ├── compute_input.py
│   │   ├── data_nft.py
│   │   ├── data_nft_factory.py
│   │   ├── datatoken1.py
│   │   ├── datatoken2.py
│   │   ├── datatoken_base.py
│   │   ├── df/
│   │   │   ├── df_rewards.py
│   │   │   ├── df_strategy_v1.py
│   │   │   └── test/
│   │   │       ├── conftest.py
│   │   │       ├── test_df_rewards.py
│   │   │       └── test_df_strategy_v1.py
│   │   ├── dispenser.py
│   │   ├── erc721_token_factory_base.py
│   │   ├── factory_router.py
│   │   ├── fixed_rate_exchange.py
│   │   ├── test/
│   │   │   ├── __init__.py
│   │   │   ├── conftest.py
│   │   │   ├── test_data_nft.py
│   │   │   ├── test_data_nft_factory.py
│   │   │   ├── test_datatoken.py
│   │   │   ├── test_datatoken_order_both_templates.py
│   │   │   ├── test_dispenser.py
│   │   │   ├── test_exchange_fees.py
│   │   │   ├── test_exchange_main.py
│   │   │   ├── test_factory_router.py
│   │   │   └── test_fake_ocean.py
│   │   └── ve/
│   │       ├── smart_wallet_checker.py
│   │       ├── test/
│   │       │   ├── conftest.py
│   │       │   ├── test_smart_wallet_checker.py
│   │       │   ├── test_ve_allocate.py
│   │       │   ├── test_ve_delegation.py
│   │       │   ├── test_ve_fee_distributor.py
│   │       │   ├── test_ve_fee_estimate.py
│   │       │   └── test_ve_ocean.py
│   │       ├── ve_allocate.py
│   │       ├── ve_delegation.py
│   │       ├── ve_fee_distributor.py
│   │       ├── ve_fee_estimate.py
│   │       └── ve_ocean.py
│   ├── ocean/
│   │   ├── __init__.py
│   │   ├── crypto.py
│   │   ├── mint_fake_ocean.py
│   │   ├── ocean.py
│   │   ├── ocean_assets.py
│   │   ├── ocean_compute.py
│   │   ├── test/
│   │   │   ├── conftest.py
│   │   │   ├── test_crypto.py
│   │   │   ├── test_ocean.py
│   │   │   ├── test_ocean_assets.py
│   │   │   └── test_util.py
│   │   └── util.py
│   ├── services/
│   │   ├── consumer_parameters.py
│   │   ├── service.py
│   │   └── test/
│   │       ├── conftest.py
│   │       ├── test_consumer_parameters.py
│   │       └── test_service.py
│   ├── structures/
│   │   ├── abi_tuples.py
│   │   ├── algorithm_metadata.py
│   │   ├── file_objects.py
│   │   └── test/
│   │       ├── test_algorithm_metadata.py
│   │       └── test_file_objects.py
│   ├── test/
│   │   ├── __init__.py
│   │   ├── test_config.py
│   │   └── test_example_config.py
│   └── web3_internal/
│       ├── __init__.py
│       ├── clef.py
│       ├── constants.py
│       ├── contract_base.py
│       ├── contract_utils.py
│       ├── http_provider.py
│       ├── request.py
│       ├── test/
│       │   ├── __init__.py
│       │   ├── conftest.py
│       │   ├── test_contract_base.py
│       │   ├── test_contract_utils.py
│       │   └── test_wallet.py
│       └── utils.py
├── pyproject.toml
├── pytest.ini
├── requirements_dev.txt
├── setup.cfg
├── setup.py
└── tests/
    ├── __init__.py
    ├── flows/
    │   ├── __init__.py
    │   ├── conftest.py
    │   └── test_start_reuse_order_fees.py
    ├── generated-readmes/
    │   └── __init__.py
    ├── integration/
    │   ├── ganache/
    │   │   ├── conftest.py
    │   │   ├── test_compute_flow.py
    │   │   ├── test_consume_flow.py
    │   │   ├── test_disconnecting_components.py
    │   │   ├── test_graphql.py
    │   │   ├── test_market_flow.py
    │   │   └── test_onchain.py
    │   └── remote/
    │       ├── __init__.py
    │       ├── test_mumbai_main.py
    │       ├── test_mumbai_readme.py
    │       ├── test_polygon.py
    │       └── util.py
    ├── readmes/
    │   ├── conftest.py
    │   └── test_readmes.py
    └── resources/
        ├── __init__.py
        ├── ddo/
        │   ├── ddo_algorithm.json
        │   ├── ddo_algorithm2.json
        │   ├── ddo_sa_sample.json
        │   ├── ddo_sa_sample_disabled.json
        │   ├── ddo_sa_sample_with_credentials.json
        │   ├── ddo_sample_algorithm.json
        │   ├── ddo_v4_sample.json
        │   ├── ddo_v4_with_compute_service.json
        │   ├── ddo_v4_with_compute_service2.json
        │   ├── ddo_with_compute_service.json
        │   └── valid_metadata.json
        ├── ddo_helpers.py
        ├── helper_functions.py
        ├── keys/
        │   ├── key_file_1.json
        │   └── key_file_2.json
        ├── mocks/
        │   ├── __init__.py
        │   ├── data_provider_mock.py
        │   └── http_client_mock.py
        └── test/
            └── test_helper_functions.py
Download .txt
SYMBOL INDEX (656 symbols across 103 files)

FILE: conftest_ganache.py
  function setup_all (line 40) | def setup_all(request, config, ocean_token):
  function config (line 71) | def config():
  function publisher_ocean (line 76) | def publisher_ocean():
  function basic_asset (line 81) | def basic_asset(publisher_ocean, publisher_wallet):
  function consumer_ocean (line 96) | def consumer_ocean():
  function publisher_wallet (line 101) | def publisher_wallet():
  function consumer_wallet (line 106) | def consumer_wallet():
  function another_consumer_wallet (line 111) | def another_consumer_wallet():
  function factory_deployer_wallet (line 116) | def factory_deployer_wallet(config):
  function ocean_address (line 121) | def ocean_address(config) -> str:
  function ocean_token (line 126) | def ocean_token(config, ocean_address) -> Datatoken1:
  function factory_router (line 131) | def factory_router(config):
  function data_nft_factory (line 136) | def data_nft_factory(config):
  function provider_wallet (line 141) | def provider_wallet():
  function file1 (line 146) | def file1():
  function file2 (line 151) | def file2():
  function file3 (line 156) | def file3():
  function FRE (line 161) | def FRE(config) -> FixedRateExchange:
  function data_nft (line 166) | def data_nft(config, publisher_wallet) -> DataNFT:
  function data_NFT_and_DT (line 171) | def data_NFT_and_DT(config, publisher_wallet) -> Tuple[DataNFT, Datatoke...
  function DT (line 176) | def DT(data_NFT_and_DT) -> Datatoken1:
  function OCEAN (line 183) | def OCEAN(ocean_token) -> Datatoken1:
  function alice (line 188) | def alice(publisher_wallet):
  function bob (line 193) | def bob(consumer_wallet):
  function carlos (line 198) | def carlos():
  function dan (line 203) | def dan():

FILE: ocean_lib/agreements/consumable.py
  class ConsumableCodes (line 8) | class ConsumableCodes:
  class MalformedCredential (line 26) | class MalformedCredential(Exception):
  class AssetNotConsumable (line 30) | class AssetNotConsumable(Exception):
    method __init__ (line 32) | def __init__(self, consumable_code: int) -> None:

FILE: ocean_lib/agreements/service_types.py
  class ServiceTypes (line 8) | class ServiceTypes:
  class ServiceTypesNames (line 16) | class ServiceTypesNames:

FILE: ocean_lib/aquarius/aquarius.py
  class Aquarius (line 23) | class Aquarius:
    method __init__ (line 27) | def __init__(self, aquarius_url: str) -> None:
    method get_instance (line 54) | def get_instance(cls, metadata_cache_uri: str) -> "Aquarius":
    method get_ddo (line 58) | def get_ddo(self, did: str) -> Optional[DDO]:
    method ddo_exists (line 70) | def ddo_exists(self, did: str) -> bool:
    method get_ddo_metadata (line 76) | def get_ddo_metadata(self, did: str) -> dict:
    method query_search (line 85) | def query_search(self, search_query: dict) -> list:
    method validate_ddo (line 112) | def validate_ddo(self, ddo: DDO) -> Tuple[bool, Union[list, dict]]:
    method wait_for_ddo (line 133) | def wait_for_ddo(self, did: str, timeout=60):
    method wait_for_ddo_update (line 148) | def wait_for_ddo_update(self, ddo: DDO, tx: str):

FILE: ocean_lib/aquarius/test/test_aquarius.py
  function test_init (line 13) | def test_init():
  function test_aqua_functions_for_single_ddo (line 20) | def test_aqua_functions_for_single_ddo(publisher_ocean, publisher_wallet...
  function test_invalid_search_query (line 44) | def test_invalid_search_query():
  function test_empty_responses (line 53) | def test_empty_responses():

FILE: ocean_lib/assets/asset_downloader.py
  function download_asset_files (line 21) | def download_asset_files(
  function is_consumable (line 87) | def is_consumable(

FILE: ocean_lib/assets/credentials.py
  class AddressCredentialMixin (line 12) | class AddressCredentialMixin:
    method get_addresses_of_class (line 14) | def get_addresses_of_class(self, access_class: str = "allow") -> list:
    method requires_credential (line 26) | def requires_credential(self) -> bool:
    method validate_access (line 34) | def validate_access(self, credential: Optional[dict] = None) -> int:
    method add_address_to_access_class (line 53) | def add_address_to_access_class(
    method remove_address_from_access_class (line 79) | def remove_address_from_access_class(
    method get_address_entry_of_class (line 102) | def get_address_entry_of_class(self, access_class: str = "allow") -> O...
  function simplify_credential_to_address (line 110) | def simplify_credential_to_address(credential: Optional[dict]) -> Option...

FILE: ocean_lib/assets/ddo.py
  class DDO (line 19) | class DDO(AddressCredentialMixin):
    method __init__ (line 23) | def __init__(
    method requires_address_credential (line 52) | def requires_address_credential(self) -> bool:
    method allowed_addresses (line 58) | def allowed_addresses(self) -> list:
    method denied_addresses (line 64) | def denied_addresses(self) -> list:
    method add_address_to_allow_list (line 69) | def add_address_to_allow_list(self, address: str) -> None:
    method add_address_to_deny_list (line 74) | def add_address_to_deny_list(self, address: str) -> None:
    method remove_address_from_allow_list (line 79) | def remove_address_from_allow_list(self, address: str) -> None:
    method remove_address_from_deny_list (line 84) | def remove_address_from_deny_list(self, address: str) -> None:
    method from_dict (line 90) | def from_dict(cls, dictionary: dict) -> "DDO":
    method as_dictionary (line 120) | def as_dictionary(self) -> dict:
    method add_service (line 149) | def add_service(self, service: Service) -> None:
    method create_compute_service (line 163) | def create_compute_service(
    method get_service_by_id (line 193) | def get_service_by_id(self, service_id: str) -> Service:
    method get_service_by_index (line 201) | def get_service_by_index(self, service_index: int) -> Service:
    method get_index_of_service (line 209) | def get_index_of_service(self, service: Service) -> int:
    method generate_trusted_algorithms (line 222) | def generate_trusted_algorithms(self) -> dict:
    method is_disabled (line 238) | def is_disabled(self) -> bool:
  class UnavailableDDO (line 242) | class UnavailableDDO(DDO):

FILE: ocean_lib/assets/test/test_asset_downloader.py
  function test_is_consumable (line 23) | def test_is_consumable():
  function test_ocean_assets_download_failure (line 47) | def test_ocean_assets_download_failure(publisher_wallet):
  function test_invalid_provider_uri (line 67) | def test_invalid_provider_uri(publisher_wallet):
  function test_invalid_state (line 84) | def test_invalid_state(publisher_wallet):
  function test_ocean_assets_download_indexes (line 111) | def test_ocean_assets_download_indexes(publisher_wallet):
  function test_ocean_assets_download_destination_file (line 141) | def test_ocean_assets_download_destination_file(

FILE: ocean_lib/assets/test/test_ddo.py
  function test_ddo_utils (line 19) | def test_ddo_utils():
  function test_add_service (line 125) | def test_add_service():
  function test_get_service_by_id (line 203) | def test_get_service_by_id():
  function test_credentials (line 220) | def test_credentials():
  function test_credential_simplification (line 271) | def test_credential_simplification():
  function test_is_disabled (line 281) | def test_is_disabled():

FILE: ocean_lib/data_provider/base.py
  class DataServiceProviderBase (line 29) | class DataServiceProviderBase:
    method get_http_client (line 37) | def get_http_client() -> Session:
    method set_http_client (line 43) | def set_http_client(http_client: Session) -> None:
    method sign_message (line 49) | def sign_message(wallet, msg: str, provider_uri: str) -> Tuple[str, str]:
    method get_url (line 79) | def get_url(config_dict: dict) -> str:
    method get_service_endpoints (line 89) | def get_service_endpoints(provider_uri: str) -> Dict[str, List[str]]:
    method get_c2d_environments (line 101) | def get_c2d_environments(provider_uri: str, chain_id: int) -> Optional...
    method get_provider_address (line 127) | def get_provider_address(provider_uri: str, chain_id: int) -> Optional...
    method get_root_uri (line 150) | def get_root_uri(service_endpoint: str) -> str:
    method is_valid_provider (line 190) | def is_valid_provider(provider_uri: str) -> bool:
    method build_endpoint (line 200) | def build_endpoint(
    method write_file (line 218) | def write_file(
    method _validate_content_disposition (line 241) | def _validate_content_disposition(header: str) -> bool:
    method _get_file_name (line 247) | def _get_file_name(response: Response) -> Optional[str]:
    method _http_method (line 267) | def _http_method(method: str, *args, **kwargs) -> Optional[Union[Mock,...
    method check_response (line 280) | def check_response(
  function urljoin (line 317) | def urljoin(*args) -> str:
  function _remove_slash (line 323) | def _remove_slash(path: str) -> str:

FILE: ocean_lib/data_provider/data_encryptor.py
  class DataEncryptor (line 20) | class DataEncryptor(DataServiceProviderBase):
    method encrypt (line 25) | def encrypt(

FILE: ocean_lib/data_provider/data_service_provider.py
  class DataServiceProvider (line 26) | class DataServiceProvider(DataServiceProviderBase):
    method initialize (line 39) | def initialize(
    method initialize_compute (line 76) | def initialize_compute(
    method download (line 124) | def download(
    method start_compute_job (line 182) | def start_compute_job(
    method stop_compute_job (line 258) | def stop_compute_job(
    method delete_compute_job (line 282) | def delete_compute_job(
    method compute_job_status (line 306) | def compute_job_status(
    method compute_job_result (line 331) | def compute_job_result(
    method compute_job_result_logs (line 378) | def compute_job_result_logs(
    method _send_compute_request (line 412) | def _send_compute_request(
    method _prepare_compute_payload (line 450) | def _prepare_compute_payload(
    method check_single_file_info (line 524) | def check_single_file_info(url_object: dict, provider_uri: str) -> bool:
    method check_asset_file_info (line 535) | def check_asset_file_info(

FILE: ocean_lib/data_provider/fileinfo_provider.py
  class FileInfoProvider (line 19) | class FileInfoProvider(DataServiceProviderBase):
    method fileinfo (line 32) | def fileinfo(

FILE: ocean_lib/data_provider/test/test_base.py
  function test_validate_content_disposition (line 10) | def test_validate_content_disposition():
  function test_get_file_name (line 20) | def test_get_file_name(caplog):

FILE: ocean_lib/data_provider/test/test_data_service_provider.py
  function with_evil_client (line 39) | def with_evil_client():
  function with_nice_client (line 47) | def with_nice_client():
  function with_empty_client (line 55) | def with_empty_client():
  function test_set_http_client (line 62) | def test_set_http_client(with_nice_client):
  function test_initialize_fails (line 68) | def test_initialize_fails():
  function test_start_compute_job_fails_empty (line 102) | def test_start_compute_job_fails_empty(consumer_wallet):
  function test_send_compute_request_failure (line 139) | def test_send_compute_request_failure(with_evil_client, provider_wallet):
  function test_compute_job_result_fails (line 148) | def test_compute_job_result_fails(provider_wallet):
  function test_delete_job_result (line 167) | def test_delete_job_result(provider_wallet):
  function test_encrypt (line 193) | def test_encrypt(provider_wallet, file1, file2):
  function test_fileinfo_and_initialize (line 226) | def test_fileinfo_and_initialize(publisher_wallet, publisher_ocean, ocea...
  function test_invalid_file_name (line 260) | def test_invalid_file_name():
  function test_expose_endpoints (line 268) | def test_expose_endpoints():
  function test_c2d_environments (line 280) | def test_c2d_environments():
  function test_provider_address (line 289) | def test_provider_address():
  function test_get_root_uri (line 299) | def test_get_root_uri():
  function test_build_endpoint (line 344) | def test_build_endpoint():
  function test_build_specific_endpoints (line 369) | def test_build_specific_endpoints():
  function test_check_single_file_info (line 405) | def test_check_single_file_info():
  function test_encrypt_failure (line 417) | def test_encrypt_failure():
  function test_fileinfo_failure (line 435) | def test_fileinfo_failure():
  function test_initialize_failure (line 457) | def test_initialize_failure():
  function test_initialize_compute_failure (line 479) | def test_initialize_compute_failure():
  function test_job_result_failure (line 522) | def test_job_result_failure(consumer_wallet):
  function test_check_asset_failure (line 538) | def test_check_asset_failure():

FILE: ocean_lib/example_config.py
  function get_config_dict (line 60) | def get_config_dict(network_url: Optional[str] = None) -> dict:
  function get_web3 (line 104) | def get_web3(network_url: str) -> Web3:

FILE: ocean_lib/exceptions.py
  class OceanEncryptAssetUrlsError (line 7) | class OceanEncryptAssetUrlsError(Exception):
  class InsufficientBalance (line 11) | class InsufficientBalance(Exception):
  class AquariusError (line 15) | class AquariusError(Exception):
  class VerifyTxFailed (line 19) | class VerifyTxFailed(Exception):
  class TransactionFailed (line 23) | class TransactionFailed(Exception):
  class DataProviderException (line 27) | class DataProviderException(Exception):

FILE: ocean_lib/http_requests/requests_session.py
  class TimeoutHTTPAdapter (line 11) | class TimeoutHTTPAdapter(HTTPAdapter):
    method __init__ (line 12) | def __init__(self, *args, **kwargs):
    method send (line 19) | def send(self, request, **kwargs):
  function get_requests_session (line 26) | def get_requests_session() -> Session:

FILE: ocean_lib/models/compute_input.py
  class ComputeInput (line 14) | class ComputeInput:
    method __init__ (line 16) | def __init__(
    method as_dictionary (line 47) | def as_dictionary(self) -> Dict[str, Union[str, Dict]]:

FILE: ocean_lib/models/data_nft.py
  class DataNFTPermissions (line 262) | class DataNFTPermissions(IntEnum):
  class MetadataState (line 269) | class MetadataState(IntEnum):
  class Flags (line 277) | class Flags(IntFlag):
    method to_byte (line 282) | def to_byte(self):
  class DataNFT (line 287) | class DataNFT(ContractBase):
    method create_datatoken (line 290) | def create_datatoken(self, tx_dict, *args, **kwargs) -> DatatokenBase:
    method calculate_did (line 295) | def calculate_did(self):
    method set_data (line 299) | def set_data(self, field_label: str, field_value: str, tx_dict: dict):
    method get_data (line 306) | def get_data(self, field_label: str) -> str:
  class DataNFTArguments (line 314) | class DataNFTArguments:
    method __init__ (line 315) | def __init__(
    method get_default_token_uri (line 345) | def get_default_token_uri(self):
    method deploy_contract (line 357) | def deploy_contract(self, config_dict, tx_dict) -> DataNFT:

FILE: ocean_lib/models/data_nft_factory.py
  class DataNFTFactoryContract (line 71) | class DataNFTFactoryContract(ERC721TokenFactoryBase):
    method verify_nft (line 75) | def verify_nft(self, nft_address: str) -> bool:
    method create (line 84) | def create(self, tx_dict, *args, **kwargs):
    method start_multiple_token_order (line 90) | def start_multiple_token_order(self, orders: List[OrderData], tx_dict:...
    method reuse_multiple_token_order (line 121) | def reuse_multiple_token_order(
    method create_with_erc20 (line 135) | def create_with_erc20(
    method create_with_erc20_and_fixed_rate (line 189) | def create_with_erc20_and_fixed_rate(
    method create_with_erc20_and_dispenser (line 257) | def create_with_erc20_and_dispenser(
    method create_with_metadata (line 321) | def create_with_metadata(
    method search_exchange_by_datatoken (line 364) | def search_exchange_by_datatoken(
    method get_token_address (line 384) | def get_token_address(self, receipt):
    method check_datatoken (line 391) | def check_datatoken(self, datatoken_address: str) -> bool:
    method check_nft (line 395) | def check_nft(self, nft_address: str) -> bool:

FILE: ocean_lib/models/datatoken1.py
  class Datatoken1 (line 194) | class Datatoken1(DatatokenBase):
    method dispense_and_order (line 204) | def dispense_and_order(
    method buy_DT_and_order (line 247) | def buy_DT_and_order(

FILE: ocean_lib/models/datatoken2.py
  class Datatoken2 (line 25) | class Datatoken2(DatatokenBase):
    method buy_DT_and_order (line 29) | def buy_DT_and_order(
    method dispense_and_order (line 87) | def dispense_and_order(

FILE: ocean_lib/models/datatoken_base.py
  class TokenFeeInfo (line 32) | class TokenFeeInfo:
    method __init__ (line 33) | def __init__(
    method to_tuple (line 46) | def to_tuple(self):
    method from_tuple (line 50) | def from_tuple(cls, tup):
    method __str__ (line 54) | def __str__(self):
  class DatatokenArguments (line 64) | class DatatokenArguments:
    method __init__ (line 65) | def __init__(
    method create_datatoken (line 97) | def create_datatoken(self, data_nft, tx_dict, with_services=False):
  class DatatokenRoles (line 151) | class DatatokenRoles(IntEnum):
  class DatatokenBase (line 156) | class DatatokenBase(ABC, ContractBase):
    method get_typed (line 167) | def get_typed(config, address):
    method start_order (line 181) | def start_order(
    method reuse_order (line 210) | def reuse_order(
    method get_start_order_logs (line 232) | def get_start_order_logs(
    method create_exchange (line 269) | def create_exchange(
    method get_exchanges (line 313) | def get_exchanges(self, only_active=True) -> list:
    method _FRE (line 331) | def _FRE(self):
    method create_dispenser (line 343) | def create_dispenser(self, tx_dict: dict, *args, **kwargs):
    method get_dispensers (line 370) | def get_dispensers(self, only_active=True) -> list:
    method dispense (line 385) | def dispense(self, amount: Union[int, str], tx_dict: dict):
    method dispenser_status (line 404) | def dispenser_status(self):
    method _ocean_dispenser (line 413) | def _ocean_dispenser(self):
    method build_access_service (line 422) | def build_access_service(
    method get_publish_market_order_fees (line 440) | def get_publish_market_order_fees(self):
    method get_from_pricing_schema_and_order (line 443) | def get_from_pricing_schema_and_order(self, *args, **kwargs):
  class MockERC20 (line 496) | class MockERC20(DatatokenBase):
    method getId (line 499) | def getId(self):
  class MockOcean (line 503) | class MockOcean(DatatokenBase):
    method getId (line 506) | def getId(self):

FILE: ocean_lib/models/df/df_rewards.py
  class DFRewards (line 8) | class DFRewards(ContractBase):

FILE: ocean_lib/models/df/df_strategy_v1.py
  class DFStrategyV1 (line 8) | class DFStrategyV1(ContractBase):

FILE: ocean_lib/models/df/test/conftest.py
  function ocean (line 11) | def ocean(publisher_ocean):

FILE: ocean_lib/models/df/test/test_df_rewards.py
  function test1 (line 9) | def test1(ocean):

FILE: ocean_lib/models/df/test/test_df_strategy_v1.py
  function test1 (line 9) | def test1(ocean):

FILE: ocean_lib/models/dispenser.py
  class Dispenser (line 62) | class Dispenser(ContractBase):
  class DispenserArguments (line 66) | class DispenserArguments:
    method __init__ (line 67) | def __init__(
    method to_tuple (line 79) | def to_tuple(self, config_dict):
  class DispenserStatus (line 90) | class DispenserStatus:
    method __init__ (line 93) | def __init__(self, status_tup):
    method __str__ (line 109) | def __str__(self):
  function _strWithWei (line 127) | def _strWithWei(x_wei: int) -> str:

FILE: ocean_lib/models/erc721_token_factory_base.py
  class ERC721TokenFactoryBase (line 10) | class ERC721TokenFactoryBase(ABC, ContractBase):

FILE: ocean_lib/models/factory_router.py
  class FactoryRouter (line 8) | class FactoryRouter(ContractBase):

FILE: ocean_lib/models/fixed_rate_exchange.py
  class ExchangeArguments (line 18) | class ExchangeArguments:
    method __init__ (line 19) | def __init__(
    method to_tuple (line 39) | def to_tuple(self, config_dict, tx_dict, dt_decimals=None):
  class ExchangeDetails (line 139) | class ExchangeDetails:
    method __init__ (line 140) | def __init__(self, details_tup):
    method __str__ (line 160) | def __str__(self):
  class ExchangeFeeInfo (line 180) | class ExchangeFeeInfo:
    method __init__ (line 181) | def __init__(self, fees_tup):
    method __str__ (line 194) | def __str__(self):
  class BtNeeded (line 211) | class BtNeeded:
    method __init__ (line 212) | def __init__(self, tup):
  class BtReceived (line 220) | class BtReceived:
    method __init__ (line 221) | def __init__(self, tup):
  class FixedRateExchange (line 229) | class FixedRateExchange(ContractBase):
    method get_opc_collector (line 232) | def get_opc_collector(self) -> str:
  class OneExchange (line 240) | class OneExchange:
    method __init__ (line 252) | def __init__(self, FRE: FixedRateExchange, exchange_id):
    method FRE (line 257) | def FRE(self):
    method exchange_id (line 261) | def exchange_id(self):
    method address (line 265) | def address(self):
    method BT_needed (line 273) | def BT_needed(
    method BT_received (line 290) | def BT_received(
    method buy_DT (line 307) | def buy_DT(
    method sell_DT (line 350) | def sell_DT(
    method collect_BT (line 382) | def collect_BT(self, amount: Union[int, str], tx_dict: dict):
    method collect_DT (line 397) | def collect_DT(self, amount: Union[int, str], tx_dict: dict):
    method collect_publish_market_fee (line 412) | def collect_publish_market_fee(self, tx_dict: dict):
    method collect_opc_fee (line 425) | def collect_opc_fee(self, tx_dict: dict):
    method update_publish_market_fee_collector (line 438) | def update_publish_market_fee_collector(self, new_addr: str, tx_dict):
    method update_publish_market_fee (line 443) | def update_publish_market_fee(self, new_amt: Union[str, int], tx_dict):
    method get_publish_market_fee (line 448) | def get_publish_market_fee(self) -> int:
    method set_rate (line 453) | def set_rate(self, new_rate: Union[int, str], tx_dict: dict):
    method toggle_active (line 458) | def toggle_active(self, tx_dict: dict):
    method set_allowed_swapper (line 463) | def set_allowed_swapper(self, new_addr: str, tx_dict: dict):
    method get_rate (line 468) | def get_rate(self) -> int:
    method get_dt_supply (line 473) | def get_dt_supply(self) -> int:
    method get_bt_supply (line 478) | def get_bt_supply(self) -> int:
    method details (line 483) | def details(self) -> ExchangeDetails:
    method get_allowed_swapper (line 489) | def get_allowed_swapper(self) -> str:
    method exchange_fees_info (line 494) | def exchange_fees_info(self) -> ExchangeFeeInfo:
    method is_active (line 500) | def is_active(self) -> bool:

FILE: ocean_lib/models/test/test_data_nft.py
  function test_permissions (line 25) | def test_permissions(
  function test_add_and_remove_permissions (line 182) | def test_add_and_remove_permissions(
  function test_success_update_metadata (line 222) | def test_success_update_metadata(publisher_wallet, consumer_wallet, conf...
  function test_fails_update_metadata (line 311) | def test_fails_update_metadata(consumer_wallet, publisher_wallet, config...
  function test_create_datatoken (line 333) | def test_create_datatoken(
  function test_create_datatoken_with_usdc_order_fee (line 377) | def test_create_datatoken_with_usdc_order_fee(
  function test_create_datatoken_with_non_owner (line 404) | def test_create_datatoken_with_non_owner(
  function test_fail_creating_erc20 (line 445) | def test_fail_creating_erc20(
  function test_erc721_datatoken_functions (line 467) | def test_erc721_datatoken_functions(
  function test_fail_transfer_function (line 546) | def test_fail_transfer_function(consumer_wallet, publisher_wallet, confi...
  function test_transfer_nft (line 572) | def test_transfer_nft(
  function test_nft_transfer_with_fre (line 667) | def test_nft_transfer_with_fre(
  function test_fail_create_datatoken (line 724) | def test_fail_create_datatoken(
  function test_datatoken_cap (line 761) | def test_datatoken_cap(publisher_wallet, consumer_wallet, data_nft_facto...
  function test_nft_owner_transfer (line 768) | def test_nft_owner_transfer(config, publisher_wallet, consumer_wallet, d...
  function test_set_get_data (line 811) | def test_set_get_data(data_nft, alice):

FILE: ocean_lib/models/test/test_data_nft_factory.py
  function test_nft_creation (line 26) | def test_nft_creation(
  function test_combo_functions (line 76) | def test_combo_functions(
  function test_start_multiple_order (line 186) | def test_start_multiple_order(
  function test_fail_get_templates (line 337) | def test_fail_get_templates(data_nft_factory):
  function test_nonexistent_template_index (line 349) | def test_nonexistent_template_index(data_nft_factory, publisher_wallet):

FILE: ocean_lib/models/test/test_datatoken.py
  function test_main (line 16) | def test_main(
  function test_start_order (line 104) | def test_start_order(config, publisher_wallet, consumer_wallet, data_NFT...
  function test_exceptions (line 285) | def test_exceptions(consumer_wallet, config, publisher_wallet, DT):

FILE: ocean_lib/models/test/test_datatoken_order_both_templates.py
  function test_dispense_and_order_with_non_defaults (line 18) | def test_dispense_and_order_with_non_defaults(
  function test_dispense_and_order_with_defaults (line 115) | def test_dispense_and_order_with_defaults(
  function test_buy_DT_and_order (line 145) | def test_buy_DT_and_order(

FILE: ocean_lib/models/test/test_dispenser.py
  function test_DispenserStatus (line 14) | def test_DispenserStatus():
  function test_main_flow_via_simple_ux_and_good_defaults (line 52) | def test_main_flow_via_simple_ux_and_good_defaults(
  function test_main_flow_via_simple_ux_and_setting_token_counts (line 85) | def test_main_flow_via_simple_ux_and_setting_token_counts(
  function test_main_flow_via_contract_directly (line 112) | def test_main_flow_via_contract_directly(
  function test_dispenser_creation_without_minter (line 187) | def test_dispenser_creation_without_minter(config, publisher_wallet, con...

FILE: ocean_lib/models/test/test_exchange_fees.py
  function test_exchange_swap_fees (line 47) | def test_exchange_swap_fees(
  function buy_or_sell_dt_and_verify_balances_swap_fees (line 220) | def buy_or_sell_dt_and_verify_balances_swap_fees(
  function collect_bt_or_dt_and_verify_balances (line 334) | def collect_bt_or_dt_and_verify_balances(
  function collect_fee_and_verify_balances (line 373) | def collect_fee_and_verify_balances(

FILE: ocean_lib/models/test/test_exchange_main.py
  function test_with_defaults (line 22) | def test_with_defaults(OCEAN, DT, alice, bob):
  function test_with_nondefaults (line 120) | def test_with_nondefaults(OCEAN, DT, alice, bob, carlos, dan, FRE):
  function test_ExchangeDetails (line 262) | def test_ExchangeDetails():
  function test_ExchangeFeeInfo (line 314) | def test_ExchangeFeeInfo():
  function test_BtNeeded (line 337) | def test_BtNeeded():
  function test_BtReceived (line 347) | def test_BtReceived():

FILE: ocean_lib/models/test/test_factory_router.py
  function test_router_owner (line 21) | def test_router_owner(factory_router: FactoryRouter):
  function test_swap_ocean_fee (line 26) | def test_swap_ocean_fee(factory_router: FactoryRouter):
  function test_swap_non_ocean_fee (line 31) | def test_swap_non_ocean_fee(factory_router: FactoryRouter):
  function test_is_approved_token (line 36) | def test_is_approved_token(
  function test_is_fixed_rate_contract (line 45) | def test_is_fixed_rate_contract(config: dict, factory_router: FactoryRou...
  function test_is_dispenser_contract (line 51) | def test_is_dispenser_contract(config: dict, factory_router: FactoryRout...
  function test_get_opc_fee (line 56) | def test_get_opc_fee(config: dict, factory_router: FactoryRouter, ocean_...
  function test_get_opc_fees (line 62) | def test_get_opc_fees(factory_router: FactoryRouter):
  function test_get_opc_consume_fee (line 70) | def test_get_opc_consume_fee(factory_router: FactoryRouter):
  function test_get_opc_provider_fee (line 75) | def test_get_opc_provider_fee(factory_router: FactoryRouter):
  function test_opc_collector (line 80) | def test_opc_collector(config: dict, factory_router: FactoryRouter):

FILE: ocean_lib/models/test/test_fake_ocean.py
  function test_direct_call (line 15) | def test_direct_call(config, consumer_wallet, factory_deployer_wallet, o...
  function test_use_mint_fake_ocean (line 26) | def test_use_mint_fake_ocean(config, factory_deployer_wallet, ocean_token):

FILE: ocean_lib/models/ve/smart_wallet_checker.py
  class SmartWalletChecker (line 8) | class SmartWalletChecker(ContractBase):

FILE: ocean_lib/models/ve/test/conftest.py
  function ocean (line 11) | def ocean(publisher_ocean):
  function ve_allocate (line 16) | def ve_allocate(publisher_ocean):

FILE: ocean_lib/models/ve/test/test_smart_wallet_checker.py
  function test1 (line 9) | def test1(ocean):

FILE: ocean_lib/models/ve/test/test_ve_allocate.py
  function test_single_allocation (line 12) | def test_single_allocation(ve_allocate):
  function test_single_events (line 38) | def test_single_events(ve_allocate):
  function test_batch_allocation (line 58) | def test_batch_allocation(ve_allocate):
  function test_batch_events (line 74) | def test_batch_events(ve_allocate):

FILE: ocean_lib/models/ve/test/test_ve_delegation.py
  function test1 (line 9) | def test1(ocean):

FILE: ocean_lib/models/ve/test/test_ve_fee_distributor.py
  function test1 (line 9) | def test1(ocean, consumer_wallet):

FILE: ocean_lib/models/ve/test/test_ve_fee_estimate.py
  function test1 (line 9) | def test1(ocean):

FILE: ocean_lib/models/ve/test/test_ve_ocean.py
  function test_ve_ocean1 (line 16) | def test_ve_ocean1(ocean, factory_deployer_wallet, ocean_token):

FILE: ocean_lib/models/ve/ve_allocate.py
  class VeAllocate (line 8) | class VeAllocate(ContractBase):

FILE: ocean_lib/models/ve/ve_delegation.py
  class VeDelegation (line 8) | class VeDelegation(ContractBase):

FILE: ocean_lib/models/ve/ve_fee_distributor.py
  class VeFeeDistributor (line 8) | class VeFeeDistributor(ContractBase):

FILE: ocean_lib/models/ve/ve_fee_estimate.py
  class VeFeeEstimate (line 8) | class VeFeeEstimate(ContractBase):

FILE: ocean_lib/models/ve/ve_ocean.py
  class VeOcean (line 8) | class VeOcean(ContractBase):

FILE: ocean_lib/ocean/crypto.py
  function calc_symkey (line 18) | def calc_symkey(base_str: str) -> str:
  function sym_encrypt (line 28) | def sym_encrypt(value: str, symkey: str) -> str:
  function sym_decrypt (line 38) | def sym_decrypt(value_enc: str, symkey: str) -> str:
  function calc_pubkey (line 48) | def calc_pubkey(privkey: str) -> str:
  function asym_encrypt (line 55) | def asym_encrypt(value: str, pubkey: str) -> str:
  function asym_decrypt (line 64) | def asym_decrypt(value_enc_h: str, privkey: str) -> str:

FILE: ocean_lib/ocean/mint_fake_ocean.py
  function mint_fake_OCEAN (line 15) | def mint_fake_OCEAN(config: dict) -> None:

FILE: ocean_lib/ocean/ocean.py
  class Ocean (line 41) | class Ocean:
    method __init__ (line 45) | def __init__(self, config_dict: Dict, data_provider: Optional[Type] = ...
    method OCEAN_address (line 103) | def OCEAN_address(self) -> str:
    method OCEAN_token (line 108) | def OCEAN_token(self) -> DatatokenBase:
    method OCEAN (line 113) | def OCEAN(self):  # alias for OCEAN_token
    method data_nft_factory (line 120) | def data_nft_factory(self) -> DataNFTFactoryContract:
    method dispenser (line 125) | def dispenser(self) -> Dispenser:
    method fixed_rate_exchange (line 130) | def fixed_rate_exchange(self) -> FixedRateExchange:
    method factory_router (line 135) | def factory_router(self) -> FactoryRouter:
    method get_nft_token (line 141) | def get_nft_token(self, token_address: str) -> DataNFT:
    method get_datatoken (line 149) | def get_datatoken(self, token_address: str) -> DatatokenBase:
    method get_user_orders (line 159) | def get_user_orders(self, address: str, datatoken: str) -> List[Attrib...
    method retrieve_provider_fees (line 180) | def retrieve_provider_fees(
    method retrieve_provider_fees_for_compute (line 192) | def retrieve_provider_fees_for_compute(
    method df_rewards (line 215) | def df_rewards(self) -> DFRewards:
    method df_strategy_v1 (line 220) | def df_strategy_v1(self) -> DFStrategyV1:
    method smart_wallet_checker (line 225) | def smart_wallet_checker(self) -> SmartWalletChecker:
    method ve_allocate (line 230) | def ve_allocate(self) -> VeAllocate:
    method ve_delegation (line 235) | def ve_delegation(self) -> VeDelegation:
    method ve_fee_distributor (line 240) | def ve_fee_distributor(self) -> VeFeeDistributor:
    method ve_fee_estimate (line 245) | def ve_fee_estimate(self) -> VeFeeEstimate:
    method ve_ocean (line 250) | def ve_ocean(self) -> VeOcean:
    method veOCEAN (line 255) | def veOCEAN(self) -> VeOcean:  # alias for ve_ocean
    method config (line 262) | def config(self) -> dict:  # alias for config_dict
    method _addr (line 266) | def _addr(self, type_str: str) -> str:
    method wallet_balance (line 269) | def wallet_balance(self, w):

FILE: ocean_lib/ocean/ocean_assets.py
  class AssetArguments (line 55) | class AssetArguments:
    method __init__ (line 56) | def __init__(
  class OceanAssets (line 77) | class OceanAssets:
    method __init__ (line 81) | def __init__(self, config_dict, data_provider: Type[DataServiceProvide...
    method validate (line 98) | def validate(self, ddo: DDO) -> Tuple[bool, list]:
    method _encrypt_ddo (line 116) | def _encrypt_ddo(
    method _assert_ddo_metadata (line 171) | def _assert_ddo_metadata(metadata: dict):
    method create_algo_asset (line 186) | def create_algo_asset(
    method create_url_asset (line 223) | def create_url_asset(
    method create_arweave_asset (line 241) | def create_arweave_asset(
    method create_graphql_asset (line 254) | def create_graphql_asset(
    method create_onchain_asset (line 267) | def create_onchain_asset(
    method default_metadata (line 294) | def default_metadata(cls, name: str, tx_dict: dict, type="dataset") ->...
    method create_bundled (line 310) | def create_bundled(
    method create (line 407) | def create(
    method update (line 541) | def update(
    method resolve (line 607) | def resolve(self, did: str) -> "DDO":
    method search (line 611) | def search(self, text: str) -> list:
    method query (line 628) | def query(self, query: dict) -> list:
    method download_asset (line 643) | def download_asset(
    method pay_for_access_service (line 669) | def pay_for_access_service(
    method pay_for_compute_service (line 744) | def pay_for_compute_service(
    method _start_or_reuse_order_based_on_initialize_response (line 801) | def _start_or_reuse_order_based_on_initialize_response(

FILE: ocean_lib/ocean/ocean_compute.py
  class OceanCompute (line 23) | class OceanCompute:
    method __init__ (line 25) | def __init__(
    method start (line 33) | def start(
    method status (line 73) | def status(self, ddo: DDO, service: Service, job_id: str, wallet) -> D...
    method result (line 91) | def result(
    method compute_job_result_logs (line 109) | def compute_job_result_logs(
    method stop (line 133) | def stop(self, ddo: DDO, service: Service, job_id: str, wallet) -> Dic...
    method get_c2d_environments (line 149) | def get_c2d_environments(self, service_endpoint: str, chain_id: int) -...
    method get_free_c2d_environment (line 153) | def get_free_c2d_environment(self, service_endpoint: str, chain_id) ->...

FILE: ocean_lib/ocean/test/test_crypto.py
  function test_symkey (line 11) | def test_symkey():
  function test_sym_encrypt_decrypt (line 20) | def test_sym_encrypt_decrypt():
  function test_asym_encrypt_decrypt (line 32) | def test_asym_encrypt_decrypt(alice):

FILE: ocean_lib/ocean/test/test_ocean.py
  function test_nft_factory (line 24) | def test_nft_factory(config, publisher_ocean, publisher_wallet):
  function test_contract_objects (line 36) | def test_contract_objects(publisher_ocean):

FILE: ocean_lib/ocean/test/test_ocean_assets.py
  function test_register_asset (line 37) | def test_register_asset(publisher_ocean):
  function test_update (line 43) | def test_update(publisher_ocean, publisher_wallet, config):
  function test_update_datatokens (line 87) | def test_update_datatokens(publisher_ocean, publisher_wallet, config, fi...
  function test_ocean_assets_search (line 162) | def test_ocean_assets_search():
  function test_ocean_assets_validate (line 168) | def test_ocean_assets_validate(publisher_ocean):
  function test_ocean_assets_algorithm (line 185) | def test_ocean_assets_algorithm():
  function test_download_fails (line 191) | def test_download_fails(publisher_ocean, publisher_wallet):
  function test_create_bad_metadata (line 216) | def test_create_bad_metadata(publisher_ocean, publisher_wallet):
  function test_create_url_asset (line 240) | def test_create_url_asset():
  function test_plain_asset_with_one_datatoken (line 246) | def test_plain_asset_with_one_datatoken(publisher_ocean, publisher_walle...
  function test_plain_asset_multiple_datatokens (line 274) | def test_plain_asset_multiple_datatokens(publisher_ocean, publisher_wall...
  function test_plain_asset_multiple_services (line 314) | def test_plain_asset_multiple_services(publisher_ocean, publisher_wallet...
  function test_encrypted_asset (line 372) | def test_encrypted_asset(publisher_ocean, publisher_wallet, config):
  function test_compressed_asset (line 398) | def test_compressed_asset(publisher_ocean, publisher_wallet, config):
  function test_compressed_and_encrypted_asset (line 424) | def test_compressed_and_encrypted_asset(publisher_ocean, publisher_walle...
  function test_asset_creation_errors (line 450) | def test_asset_creation_errors(publisher_ocean, publisher_wallet, config):
  function test_create_algo_asset (line 470) | def test_create_algo_asset(publisher_ocean, publisher_wallet):
  function test_create_url_asset_with_gas_strategy (line 484) | def test_create_url_asset_with_gas_strategy(
  function test_create_pricing_schemas (line 513) | def test_create_pricing_schemas(

FILE: ocean_lib/ocean/test/test_util.py
  function test_get_ocean_token_address (line 20) | def test_get_ocean_token_address(config):
  function test_get_address_by_type (line 32) | def test_get_address_by_type(config):
  function test_get_address_of_type_failure (line 41) | def test_get_address_of_type_failure(config):
  function test_wei (line 47) | def test_wei():

FILE: ocean_lib/ocean/util.py
  function get_address_of_type (line 17) | def get_address_of_type(
  function get_ocean_token_address (line 32) | def get_ocean_token_address(config_dict: dict) -> str:
  function create_checksum (line 44) | def create_checksum(text: str) -> str:
  function from_wei (line 52) | def from_wei(amt_wei: int):
  function to_wei (line 57) | def to_wei(amt_eth) -> int:
  function str_with_wei (line 62) | def str_with_wei(amt_wei: int) -> str:
  function get_from_address (line 67) | def get_from_address(tx_dict: dict) -> str:
  function get_args_object (line 74) | def get_args_object(args, kwargs, args_class):
  function send_ether (line 91) | def send_ether(

FILE: ocean_lib/services/consumer_parameters.py
  class ConsumerParameters (line 19) | class ConsumerParameters:
    method __init__ (line 20) | def __init__(
    method from_dict (line 40) | def from_dict(
    method as_dictionary (line 68) | def as_dictionary(self) -> Dict[str, Any]:
    method required_attrs (line 83) | def required_attrs():

FILE: ocean_lib/services/service.py
  class Service (line 26) | class Service:
    method __init__ (line 29) | def __init__(
    method from_dict (line 79) | def from_dict(cls, service_dict: Dict[str, Any]) -> "Service":
    method get_trusted_algorithms (line 104) | def get_trusted_algorithms(self) -> list:
    method get_trusted_algorithm_publishers (line 107) | def get_trusted_algorithm_publishers(self) -> list:
    method add_publisher_trusted_algorithm (line 111) | def add_publisher_trusted_algorithm(self, algo_ddo) -> list:
    method add_publisher_trusted_algorithm_publisher (line 138) | def add_publisher_trusted_algorithm_publisher(self, publisher_address:...
    method as_dictionary (line 162) | def as_dictionary(self) -> Dict[str, Any]:
    method remove_publisher_trusted_algorithm (line 215) | def remove_publisher_trusted_algorithm(self, algo_did: str) -> list:
    method remove_publisher_trusted_algorithm_publisher (line 236) | def remove_publisher_trusted_algorithm_publisher(
    method update_compute_values (line 265) | def update_compute_values(
    method encrypt_files (line 310) | def encrypt_files(self, nft_address: str, chain_id: int) -> Response:

FILE: ocean_lib/services/test/test_consumer_parameters.py
  function test_consumer_parameters (line 11) | def test_consumer_parameters():

FILE: ocean_lib/services/test/test_service.py
  function test_service (line 20) | def test_service():
  function test_additional_information (line 80) | def test_additional_information():
  function test_trusted_algo_functions (line 120) | def test_trusted_algo_functions(publisher_ocean):
  function test_utilitary_functions_for_trusted_algorithm_publishers (line 151) | def test_utilitary_functions_for_trusted_algorithm_publishers(publisher_...
  function test_inexistent_removals (line 194) | def test_inexistent_removals():
  function test_utilitary_functions_for_trusted_algorithms (line 217) | def test_utilitary_functions_for_trusted_algorithms(publisher_ocean):
  function test_add_trusted_algorithm_no_compute_service (line 288) | def test_add_trusted_algorithm_no_compute_service(publisher_ocean):

FILE: ocean_lib/structures/abi_tuples.py
  class OperationType (line 11) | class OperationType(Enum):

FILE: ocean_lib/structures/algorithm_metadata.py
  class AlgorithmMetadata (line 13) | class AlgorithmMetadata:
    method __init__ (line 15) | def __init__(self, metadata_dict: Dict[str, Any]) -> None:
    method is_valid (line 38) | def is_valid(self) -> bool:
    method as_json_str (line 44) | def as_json_str(self) -> str:
    method as_dictionary (line 48) | def as_dictionary(self) -> Dict[str, Any]:

FILE: ocean_lib/structures/file_objects.py
  class FilesType (line 11) | class FilesType(Protocol):
    method to_dict (line 14) | def to_dict(self) -> dict:
  class UrlFile (line 18) | class UrlFile(FilesType):
    method __init__ (line 20) | def __init__(
    method to_dict (line 29) | def to_dict(self) -> dict:
  class IpfsFile (line 41) | class IpfsFile(FilesType):
    method __init__ (line 43) | def __init__(self, hash: str) -> None:
    method to_dict (line 48) | def to_dict(self) -> dict:
  class GraphqlQuery (line 52) | class GraphqlQuery(FilesType):
    method __init__ (line 54) | def __init__(self, url: str, query: str, headers: Optional[dict] = Non...
    method to_dict (line 61) | def to_dict(self) -> dict:
  class SmartContractCall (line 70) | class SmartContractCall(FilesType):
    method __init__ (line 72) | def __init__(self, address: str, chainId: int, abi: dict) -> None:
    method to_dict (line 79) | def to_dict(self) -> dict:
  class ArweaveFile (line 88) | class ArweaveFile(FilesType):
    method __init__ (line 90) | def __init__(self, transaction_id: str) -> None:
    method to_dict (line 95) | def to_dict(self) -> dict:
  function FilesTypeFactory (line 100) | def FilesTypeFactory(file_obj: dict) -> FilesType:

FILE: ocean_lib/structures/test/test_algorithm_metadata.py
  function test_algorithm_metadata (line 13) | def test_algorithm_metadata():

FILE: ocean_lib/structures/test/test_file_objects.py
  function test_url_file (line 11) | def test_url_file():
  function test_ipfs_file (line 31) | def test_ipfs_file():
  function test_filetype_factory (line 37) | def test_filetype_factory():

FILE: ocean_lib/test/test_config.py
  function test_metadataCacheUri_config_key (line 14) | def test_metadataCacheUri_config_key():
  function test_incomplete (line 34) | def test_incomplete():

FILE: ocean_lib/test/test_example_config.py
  function test_ganache_example_config (line 19) | def test_ganache_example_config():
  function test_polygon_example_config (line 29) | def test_polygon_example_config():
  function test_get_address_of_type (line 38) | def test_get_address_of_type():

FILE: ocean_lib/web3_internal/clef.py
  function get_clef_accounts (line 12) | def get_clef_accounts(uri: str = None, timeout: int = 120) -> None:
  class ClefAccount (line 38) | class ClefAccount:
    method __init__ (line 39) | def __init__(self, address: str, provider: [HTTPProvider, IPCProvider]...

FILE: ocean_lib/web3_internal/contract_base.py
  function function_wrapper (line 23) | def function_wrapper(contract, web3, contract_functions, func_name):
  class ContractBase (line 92) | class ContractBase(object):
    method __init__ (line 99) | def __init__(self, config_dict: dict, address: Optional[str]) -> None:
    method __str__ (line 130) | def __str__(self) -> str:
    method contract_name (line 136) | def contract_name(self) -> str:
    method to_checksum_address (line 142) | def to_checksum_address(address: str) -> ChecksumAddress:
    method get_event_signature (line 152) | def get_event_signature(self, event_name: str) -> str:
    method get_logs (line 167) | def get_logs(

FILE: ocean_lib/web3_internal/contract_utils.py
  function get_contract_definition (line 22) | def get_contract_definition(contract_name: str) -> Dict[str, Any]:
  function load_contract (line 35) | def load_contract(web3: Web3, contract_name: str, address: Optional[str]...
  function get_contracts_addresses_all_networks (line 45) | def get_contracts_addresses_all_networks(config: dict):
  function get_contracts_addresses (line 59) | def get_contracts_addresses(config: dict) -> Optional[Dict[str, str]]:
  function _checksum_contract_addresses (line 80) | def _checksum_contract_addresses(

FILE: ocean_lib/web3_internal/http_provider.py
  class CustomHTTPProvider (line 22) | class CustomHTTPProvider(HTTPProvider):
    method make_request (line 27) | def make_request(self, method, params):
  function get_web3_connection_provider (line 45) | def get_web3_connection_provider(network_url):

FILE: ocean_lib/web3_internal/request.py
  function _remove_session (line 16) | def _remove_session(key, session):
  function _get_session (line 23) | def _get_session(*args, **kwargs):
  function make_post_request (line 40) | def make_post_request(endpoint_uri, data, *args, **kwargs):

FILE: ocean_lib/web3_internal/test/test_contract_base.py
  class MyFactory (line 14) | class MyFactory(ContractBase):
  function test_name_is_None (line 19) | def test_name_is_None(config):
  function test_main (line 26) | def test_main(config):

FILE: ocean_lib/web3_internal/test/test_contract_utils.py
  function test_checksum_contract_addresses (line 10) | def test_checksum_contract_addresses(monkeypatch):

FILE: ocean_lib/web3_internal/test/test_wallet.py
  function test_generating_wallets (line 14) | def test_generating_wallets(ocean_token, config):

FILE: ocean_lib/web3_internal/utils.py
  function to_32byte_hex (line 25) | def to_32byte_hex(val: int) -> str:
  function sign_with_clef (line 35) | def sign_with_clef(message_hash: str, wallet: ClefAccount) -> str:
  function sign_with_key (line 49) | def sign_with_key(message_hash: Union[HexBytes, str], key: str) -> str:
  function split_signature (line 67) | def split_signature(signature: Any) -> Signature:
  function get_gas_fees (line 87) | def get_gas_fees() -> tuple:

FILE: tests/flows/test_start_reuse_order_fees.py
  class TestStartReuseOrderFees (line 57) | class TestStartReuseOrderFees(object):
    method setup_class (line 59) | def setup_class(self):
    method test_start_order_fees (line 102) | def test_start_order_fees(
    method test_reuse_order_fees (line 261) | def test_reuse_order_fees(
  function create_asset_with_order_fee_and_timeout (line 348) | def create_asset_with_order_fee_and_timeout(
  function reuse_order_with_mock_provider_fees (line 395) | def reuse_order_with_mock_provider_fees(

FILE: tests/integration/ganache/test_compute_flow.py
  class TestComputeFlow (line 35) | class TestComputeFlow(object):
    method setup_class (line 37) | def setup_class(self):
    method wait_for_ddo (line 73) | def wait_for_ddo(self, ddo):
    method test_compute_raw_algo (line 84) | def test_compute_raw_algo(
    method test_compute_registered_algo (line 117) | def test_compute_registered_algo(
    method test_compute_reuse_order (line 138) | def test_compute_reuse_order(
    method test_compute_multi_inputs (line 160) | def test_compute_multi_inputs(
    method test_compute_trusted_algorithm (line 188) | def test_compute_trusted_algorithm(self):
    method test_compute_update_trusted_algorithm (line 193) | def test_compute_update_trusted_algorithm(
    method test_compute_trusted_publisher (line 244) | def test_compute_trusted_publisher(
    method test_compute_just_provider_fees (line 281) | def test_compute_just_provider_fees(
  function get_algorithm (line 303) | def get_algorithm(wallet, ocean_instance):
  function raw_algorithm (line 320) | def raw_algorithm():
  class AssetAndUserdata (line 341) | class AssetAndUserdata:
  function _mint_and_build_compute_input (line 346) | def _mint_and_build_compute_input(
  function run_compute_test (line 371) | def run_compute_test(

FILE: tests/integration/ganache/test_consume_flow.py
  function test_consume_asset (line 21) | def test_consume_asset(

FILE: tests/integration/ganache/test_disconnecting_components.py
  function test_with_wrong_provider (line 20) | def test_with_wrong_provider(config, caplog):
  function test_with_wrong_aquarius (line 36) | def test_with_wrong_aquarius(publisher_wallet, caplog, monkeypatch, conf...
  function _create_ddo (line 52) | def _create_ddo(ocean, publisher):
  function _iterative_create_ddo (line 71) | def _iterative_create_ddo(mock_ocean, publisher):
  function _iterative_encrypt (line 76) | def _iterative_encrypt(mock):
  function _update_with_wrong_component (line 87) | def _update_with_wrong_component(mock):

FILE: tests/integration/ganache/test_graphql.py
  function test_consume_simple_graphql_query (line 19) | def test_consume_simple_graphql_query(

FILE: tests/integration/ganache/test_market_flow.py
  function test_market_flow (line 18) | def test_market_flow(
  function test_pay_for_access_service_good_default (line 97) | def test_pay_for_access_service_good_default(

FILE: tests/integration/ganache/test_onchain.py
  function test_consume_parametrized_onchain_data (line 20) | def test_consume_parametrized_onchain_data(

FILE: tests/integration/remote/test_mumbai_main.py
  function _get_mumbai_rpc (line 13) | def _get_mumbai_rpc():
  function test_nonocean_tx (line 22) | def test_nonocean_tx(tmp_path, monkeypatch):
  function test_ocean_tx__create (line 35) | def test_ocean_tx__create(tmp_path, monkeypatch):

FILE: tests/integration/remote/test_mumbai_readme.py
  function test_simple_remote_readme (line 11) | def test_simple_remote_readme(monkeypatch):

FILE: tests/integration/remote/test_polygon.py
  function _get_polygon_rpc (line 15) | def _get_polygon_rpc():
  function test_ocean_tx__create (line 25) | def test_ocean_tx__create(tmp_path, monkeypatch):

FILE: tests/integration/remote/util.py
  function remote_config_mumbai (line 19) | def remote_config_mumbai(tmp_path):
  function remote_config_polygon (line 31) | def remote_config_polygon(tmp_path):
  function get_wallets (line 43) | def get_wallets():
  function do_nonocean_tx_and_handle_gotchas (line 62) | def do_nonocean_tx_and_handle_gotchas(ocean, alice_wallet, bob_wallet):
  function do_ocean_tx_and_handle_gotchas (line 96) | def do_ocean_tx_and_handle_gotchas(ocean, alice_wallet):
  function error_is_skippable (line 142) | def error_is_skippable(error_s: str) -> bool:
  function random_chars (line 158) | def random_chars() -> str:

FILE: tests/readmes/test_readmes.py
  class TestReadmes (line 17) | class TestReadmes(object):
    method setup_class (line 19) | def setup_class(self):
    method test_script_execution (line 34) | def test_script_execution(self, script_name):

FILE: tests/resources/ddo_helpers.py
  function get_resource_path (line 18) | def get_resource_path(dir_name, file_name):
  function get_key_from_v4_sample_ddo (line 26) | def get_key_from_v4_sample_ddo(key, file_name="ddo_v4_sample.json"):
  function get_sample_ddo (line 34) | def get_sample_ddo(file_name="ddo_v4_sample.json") -> dict:
  function get_sample_ddo_with_compute_service (line 41) | def get_sample_ddo_with_compute_service(
  function get_sample_algorithm_ddo (line 50) | def get_sample_algorithm_ddo(filename="ddo_algorithm.json") -> DDO:
  function get_default_metadata (line 61) | def get_default_metadata():
  function get_default_files (line 65) | def get_default_files():
  function build_default_services (line 69) | def build_default_services(config, datatoken):
  function build_credentials_dict (line 82) | def build_credentials_dict() -> dict:
  function get_registered_asset_with_access_service (line 87) | def get_registered_asset_with_access_service(
  function get_registered_asset_with_compute_service (line 105) | def get_registered_asset_with_compute_service(
  function get_first_service_by_type (line 129) | def get_first_service_by_type(ddo, service_type: str) -> Service:

FILE: tests/resources/helper_functions.py
  function get_wallet (line 34) | def get_wallet(index: int):
  function get_publisher_wallet (line 39) | def get_publisher_wallet():
  function get_consumer_wallet (line 44) | def get_consumer_wallet():
  function get_another_consumer_wallet (line 49) | def get_another_consumer_wallet():
  function get_provider_wallet (line 54) | def get_provider_wallet():
  function get_factory_deployer_wallet (line 58) | def get_factory_deployer_wallet(config):
  function get_ganache_wallet (line 70) | def get_ganache_wallet():
  function generate_wallet (line 77) | def generate_wallet():
  function get_ocean_instance_prerequisites (line 98) | def get_ocean_instance_prerequisites(use_provider_mock=False) -> Ocean:
  function get_publisher_ocean_instance (line 105) | def get_publisher_ocean_instance(use_provider_mock=False) -> Ocean:
  function get_consumer_ocean_instance (line 112) | def get_consumer_ocean_instance(use_provider_mock: bool = False) -> Ocean:
  function get_another_consumer_ocean_instance (line 119) | def get_another_consumer_ocean_instance(use_provider_mock: bool = False)...
  function setup_logging (line 126) | def setup_logging(
  function deploy_erc721_erc20 (line 135) | def deploy_erc721_erc20(
  function get_non_existent_nft_template (line 170) | def get_non_existent_nft_template(
  function send_mock_usdc_to_address (line 185) | def send_mock_usdc_to_address(config: dict, recipient: str, amount: int)...
  function transfer_bt_if_balance_lte (line 201) | def transfer_bt_if_balance_lte(
  function get_provider_fees (line 225) | def get_provider_fees(
  function convert_bt_amt_to_dt (line 274) | def convert_bt_amt_to_dt(
  function get_file1 (line 297) | def get_file1():
  function get_file2 (line 307) | def get_file2():
  function get_file3 (line 317) | def get_file3():
  function int_units (line 327) | def int_units(amount, num_decimals):
  function get_mock_provider_fees (line 335) | def get_mock_provider_fees(mock_type, wallet, valid_until=0):

FILE: tests/resources/mocks/data_provider_mock.py
  class DataProviderMock (line 11) | class DataProviderMock(DataServiceProvider):
    method __init__ (line 12) | def __init__(self, ocean_instance=None, wallet=None):
    method consume_service (line 27) | def consume_service(
    method start_compute_job (line 37) | def start_compute_job(*args, **kwargs):
    method stop_compute_job (line 41) | def stop_compute_job(*args, **kwargs):
    method delete_compute_job (line 45) | def delete_compute_job(*args, **kwargs):
    method compute_job_status (line 49) | def compute_job_status(*args, **kwargs):
    method compute_job_result (line 53) | def compute_job_result(*args, **kwargs):
    method compute_job_result_file (line 57) | def compute_job_result_file(*args, **kwargs):
    method get_url (line 61) | def get_url(config):

FILE: tests/resources/mocks/http_client_mock.py
  class HttpClientMockBase (line 32) | class HttpClientMockBase(Session):
    method get (line 36) | def get(cls, *args, **kwargs):
  class HttpClientEvilMock (line 54) | class HttpClientEvilMock(HttpClientMockBase):
    method post (line 58) | def post(*args, **kwargs):
    method specific_get (line 66) | def specific_get(*args, **kwargs):
  class HttpClientEmptyMock (line 74) | class HttpClientEmptyMock(HttpClientMockBase):
    method post (line 78) | def post(*args, **kwargs):
    method specific_get (line 82) | def specific_get(*args, **kwargs):
  class HttpClientNiceMock (line 86) | class HttpClientNiceMock(HttpClientMockBase):
    method specific_get (line 90) | def specific_get(*args, **kwargs):
    method return_nice_response (line 98) | def return_nice_response(indication, *args, **kwargs):
    method delete (line 107) | def delete(*args, **kwargs):
    method put (line 111) | def put(*args, **kwargs):
    method post (line 115) | def post(*args, **kwargs):

FILE: tests/resources/test/test_helper_functions.py
  function test_convert_bt_amt_to_dt (line 4) | def test_convert_bt_amt_to_dt():
Condensed preview — 195 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (723K chars).
[
  {
    "path": ".bumpversion.cfg",
    "chars": 288,
    "preview": "[bumpversion]\ncurrent_version = 3.1.2\ncommit = True\ntag = True\n\n[bumpversion:file:setup.py]\nsearch = version='{current_v"
  },
  {
    "path": ".codeclimate.yml",
    "chars": 325,
    "preview": "##\n## Copyright 2023 Ocean Protocol Foundation\n## SPDX-License-Identifier: Apache-2.0\n##\nversion: \"2\"\nchecks:\n  argument"
  },
  {
    "path": ".copyright.tmpl",
    "chars": 77,
    "preview": "Copyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n"
  },
  {
    "path": ".coveragerc",
    "chars": 20,
    "preview": "[run]\nomit = *test*\n"
  },
  {
    "path": ".docignore",
    "chars": 21,
    "preview": "**test**\nCHANGELOG.md"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 554,
    "preview": "##\n## Copyright 2023 Ocean Protocol Foundation\n## SPDX-License-Identifier: Apache-2.0\n##\n\n# To get started with Dependab"
  },
  {
    "path": ".github/workflows/black.yml",
    "chars": 314,
    "preview": "##\n## Copyright 2023 Ocean Protocol Foundation\n## SPDX-License-Identifier: Apache-2.0\n##\nname: black\n\non: [push]\n\njobs:\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "chars": 1445,
    "preview": "##\n## Copyright 2023 Ocean Protocol Foundation\n## SPDX-License-Identifier: Apache-2.0\n##\nname: Ocean.py multiple OS\n\non:"
  },
  {
    "path": ".github/workflows/libcheck.yml",
    "chars": 2921,
    "preview": "##\n## Copyright 2023 Ocean Protocol Foundation\n## SPDX-License-Identifier: Apache-2.0\n##\nname: Ocean.py library check\n\no"
  },
  {
    "path": ".github/workflows/pytest.yml",
    "chars": 2608,
    "preview": "##\n## Copyright 2023 Ocean Protocol Foundation\n## SPDX-License-Identifier: Apache-2.0\n##\nname: Ocean.py tests\n\non:\n  - p"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 882,
    "preview": "##\n## Copyright 2023 Ocean Protocol Foundation\n## SPDX-License-Identifier: Apache-2.0\n##\nname: Ocean.py release\n\non:\n  r"
  },
  {
    "path": ".gitignore",
    "chars": 240,
    "preview": ".history\n__pycache__\n.pytest_cache/\n*.pyc\n*~\n.eggs/\nartifacts/address.json\n/venv/\nocean_lib.egg-info/\n/build/\n/contracts"
  },
  {
    "path": ".pre-commit-config.yaml",
    "chars": 536,
    "preview": "##\n## Copyright 2023 Ocean Protocol Foundation\n## SPDX-License-Identifier: Apache-2.0\n##\nrepos:\n-   repo: https://github"
  },
  {
    "path": ".prospector.yml",
    "chars": 206,
    "preview": "##\n## Copyright 2023 Ocean Protocol Foundation\n## SPDX-License-Identifier: Apache-2.0\n##\npep257:\n  disable:\n    - D213\n\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 156,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\nSee [`releases`](https://github.co"
  },
  {
    "path": "LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 3807,
    "preview": "<!--\nCopyright 2025 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n> ocean.py: a Python library to p"
  },
  {
    "path": "READMEs/c2d-flow-more-examples.md",
    "chars": 5617,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n# Compute-to-Data (C2D) Flow - Mo"
  },
  {
    "path": "READMEs/c2d-flow.md",
    "chars": 8867,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n# Quickstart: Compute-to-Data (C2"
  },
  {
    "path": "READMEs/custody-light-flow.md",
    "chars": 4520,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n# Custody-light flow\n\nIt allows o"
  },
  {
    "path": "READMEs/developers.md",
    "chars": 4195,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n# Developing ocean.py\n\nThis READM"
  },
  {
    "path": "READMEs/df.md",
    "chars": 6561,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n# Quickstart: Data Farming Flow\n\nT"
  },
  {
    "path": "READMEs/gas-strategy-remote.md",
    "chars": 1500,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n# Quickstart: Use Specific Gas St"
  },
  {
    "path": "READMEs/install.md",
    "chars": 2702,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n# Install Ocean\n\n## Prerequisites\n"
  },
  {
    "path": "READMEs/key-value-private.md",
    "chars": 5989,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n# Quickstart: Private Sharing of "
  },
  {
    "path": "READMEs/key-value-public.md",
    "chars": 1961,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n# Quickstart: On-Chain Key-Value "
  },
  {
    "path": "READMEs/main-flow.md",
    "chars": 23328,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n# Main flow\n\nThis step is the fun"
  },
  {
    "path": "READMEs/parameters.md",
    "chars": 1223,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n# On Config Parameters\n\nWe can se"
  },
  {
    "path": "READMEs/predict-eth.md",
    "chars": 74,
    "preview": "This has been moved [here](https://github.com/oceanprotocol/predict-eth).\n"
  },
  {
    "path": "READMEs/profile-nfts-flow.md",
    "chars": 6201,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n# Quickstart: Profile NFTs\n\nThis "
  },
  {
    "path": "READMEs/publish-flow-credentials.md",
    "chars": 1783,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n# Quickstart: Publish & Metadata "
  },
  {
    "path": "READMEs/publish-flow-graphql.md",
    "chars": 1452,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n# Quickstart: Publish & Consume F"
  },
  {
    "path": "READMEs/publish-flow-onchain.md",
    "chars": 1483,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n# Quickstart: Publish & Consume F"
  },
  {
    "path": "READMEs/publish-flow-restapi.md",
    "chars": 2850,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n# Quickstart: Publish & Consume F"
  },
  {
    "path": "READMEs/release-process.md",
    "chars": 2090,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n# The ocean.py Release Process\n\n#"
  },
  {
    "path": "READMEs/search-and-filter-assets.md",
    "chars": 2298,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n\n# Quickstart: Search Assets Flow"
  },
  {
    "path": "READMEs/services.md",
    "chars": 2305,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n# About Ocean off-chain services\n"
  },
  {
    "path": "READMEs/setup-local.md",
    "chars": 3874,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n# Local Setup\n\nHere, we do setup "
  },
  {
    "path": "READMEs/setup-remote.md",
    "chars": 6038,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n# Remote Setup\n\nHere, we do setup"
  },
  {
    "path": "READMEs/using-clef.md",
    "chars": 3116,
    "preview": "<!--\nCopyright 2023 Ocean Protocol Foundation\nSPDX-License-Identifier: Apache-2.0\n-->\n\n# Using hardware wallets with oce"
  },
  {
    "path": "bumpversion.sh",
    "chars": 943,
    "preview": "#!/bin/bash\n##\n## Copyright 2023 Ocean Protocol Foundation\n## SPDX-License-Identifier: Apache-2.0\n##\n\nset -x\nset -e\n\nusa"
  },
  {
    "path": "conftest.py",
    "chars": 316,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\n# This is the global conftest. EVE"
  },
  {
    "path": "conftest_ganache.py",
    "chars": 4579,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom typing import Tuple\n\nimport py"
  },
  {
    "path": "ocean_lib/__init__.py",
    "chars": 200,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\n\"\"\"Initialises ocean lib package.\""
  },
  {
    "path": "ocean_lib/agreements/__init__.py",
    "chars": 85,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n"
  },
  {
    "path": "ocean_lib/agreements/consumable.py",
    "chars": 686,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom enforce_typing import enforce_"
  },
  {
    "path": "ocean_lib/agreements/service_types.py",
    "chars": 408,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\"\"\"Agreements module.\"\"\"\n\n\nclass Se"
  },
  {
    "path": "ocean_lib/aquarius/__init__.py",
    "chars": 153,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\"\"\"Ocean Aquarius module.\"\"\"\nfrom ."
  },
  {
    "path": "ocean_lib/aquarius/aquarius.py",
    "chars": 5252,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\"\"\"\nAquarius module.\nHelp to commun"
  },
  {
    "path": "ocean_lib/aquarius/test/__init__.py",
    "chars": 85,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n"
  },
  {
    "path": "ocean_lib/aquarius/test/conftest.py",
    "chars": 31,
    "preview": "from conftest_ganache import *\n"
  },
  {
    "path": "ocean_lib/aquarius/test/test_aquarius.py",
    "chars": 1806,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\n\nfrom ocean_lib.aquar"
  },
  {
    "path": "ocean_lib/assets/__init__.py",
    "chars": 85,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n"
  },
  {
    "path": "ocean_lib/assets/asset_downloader.py",
    "chars": 3300,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\nimport logging\nimport os\nfrom typi"
  },
  {
    "path": "ocean_lib/assets/credentials.py",
    "chars": 4142,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom typing import Optional\n\nfrom e"
  },
  {
    "path": "ocean_lib/assets/ddo.py",
    "chars": 7733,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport copy\nimport logging\nfrom typ"
  },
  {
    "path": "ocean_lib/assets/test/__init__.py",
    "chars": 85,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n"
  },
  {
    "path": "ocean_lib/assets/test/conftest.py",
    "chars": 31,
    "preview": "from conftest_ganache import *\n"
  },
  {
    "path": "ocean_lib/assets/test/test_asset_downloader.py",
    "chars": 5990,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport os\nfrom unittest.mock import"
  },
  {
    "path": "ocean_lib/assets/test/test_ddo.py",
    "chars": 9283,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\n\nfrom ocean_lib.agree"
  },
  {
    "path": "ocean_lib/data_provider/__init__.py",
    "chars": 85,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n"
  },
  {
    "path": "ocean_lib/data_provider/base.py",
    "chars": 10417,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\n\"\"\"Provider module.\"\"\"\nimport logg"
  },
  {
    "path": "ocean_lib/data_provider/data_encryptor.py",
    "chars": 1767,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\n\"\"\"Provider module.\"\"\"\nimport json"
  },
  {
    "path": "ocean_lib/data_provider/data_service_provider.py",
    "chars": 19247,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\n\"\"\"Provider module.\"\"\"\nimport json"
  },
  {
    "path": "ocean_lib/data_provider/fileinfo_provider.py",
    "chars": 1718,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\n\"\"\"Provider module.\"\"\"\nimport logg"
  },
  {
    "path": "ocean_lib/data_provider/test/__init__.py",
    "chars": 85,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n"
  },
  {
    "path": "ocean_lib/data_provider/test/conftest.py",
    "chars": 31,
    "preview": "from conftest_ganache import *\n"
  },
  {
    "path": "ocean_lib/data_provider/test/test_base.py",
    "chars": 1021,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom requests.models import Respons"
  },
  {
    "path": "ocean_lib/data_provider/test/test_data_service_provider.py",
    "chars": 18406,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport json\nfrom datetime import da"
  },
  {
    "path": "ocean_lib/example_config.py",
    "chars": 4147,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\nimport copy\nimport logging\nimport "
  },
  {
    "path": "ocean_lib/exceptions.py",
    "chars": 599,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\n\nclass OceanEncryptAssetUrlsError("
  },
  {
    "path": "ocean_lib/http_requests/__init__.py",
    "chars": 85,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n"
  },
  {
    "path": "ocean_lib/http_requests/requests_session.py",
    "chars": 1354,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom enforce_typing import enforce_"
  },
  {
    "path": "ocean_lib/models/__init__.py",
    "chars": 85,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n"
  },
  {
    "path": "ocean_lib/models/compute_input.py",
    "chars": 1759,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom typing import Dict, Optional, "
  },
  {
    "path": "ocean_lib/models/data_nft.py",
    "chars": 13049,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport json\nfrom base64 import b64e"
  },
  {
    "path": "ocean_lib/models/data_nft_factory.py",
    "chars": 14544,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom typing import List, Optional, "
  },
  {
    "path": "ocean_lib/models/datatoken1.py",
    "chars": 8629,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport logging\nfrom typing import A"
  },
  {
    "path": "ocean_lib/models/datatoken2.py",
    "chars": 4174,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom typing import Any, Optional, U"
  },
  {
    "path": "ocean_lib/models/datatoken_base.py",
    "chars": 16708,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport logging\nfrom abc import ABC\n"
  },
  {
    "path": "ocean_lib/models/df/df_rewards.py",
    "chars": 213,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom ocean_lib.web3_internal.contra"
  },
  {
    "path": "ocean_lib/models/df/df_strategy_v1.py",
    "chars": 219,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom ocean_lib.web3_internal.contra"
  },
  {
    "path": "ocean_lib/models/df/test/conftest.py",
    "chars": 204,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\n\nfrom conftest_ganach"
  },
  {
    "path": "ocean_lib/models/df/test/test_df_rewards.py",
    "chars": 256,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\n\n\n@pytest.mark.unit\nd"
  },
  {
    "path": "ocean_lib/models/df/test/test_df_strategy_v1.py",
    "chars": 256,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\n\n\n@pytest.mark.unit\nd"
  },
  {
    "path": "ocean_lib/models/dispenser.py",
    "chars": 4502,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom typing import Optional, Union\n"
  },
  {
    "path": "ocean_lib/models/erc721_token_factory_base.py",
    "chars": 229,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom abc import ABC\n\nfrom ocean_lib"
  },
  {
    "path": "ocean_lib/models/factory_router.py",
    "chars": 221,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom ocean_lib.web3_internal.contra"
  },
  {
    "path": "ocean_lib/models/fixed_rate_exchange.py",
    "chars": 16438,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom typing import Optional, Union\n"
  },
  {
    "path": "ocean_lib/models/test/__init__.py",
    "chars": 85,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n"
  },
  {
    "path": "ocean_lib/models/test/conftest.py",
    "chars": 116,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom conftest_ganache import *\n"
  },
  {
    "path": "ocean_lib/models/test/test_data_nft.py",
    "chars": 28232,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport json\nfrom base64 import b64d"
  },
  {
    "path": "ocean_lib/models/test/test_data_nft_factory.py",
    "chars": 12658,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\nfrom web3.logs import"
  },
  {
    "path": "ocean_lib/models/test/test_datatoken.py",
    "chars": 12603,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\nfrom web3.logs import"
  },
  {
    "path": "ocean_lib/models/test/test_datatoken_order_both_templates.py",
    "chars": 7505,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom datetime import datetime\n\nimpo"
  },
  {
    "path": "ocean_lib/models/test/test_dispenser.py",
    "chars": 7208,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\n\nfrom ocean_lib.model"
  },
  {
    "path": "ocean_lib/models/test/test_exchange_fees.py",
    "chars": 12991,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\nfrom web3.logs import"
  },
  {
    "path": "ocean_lib/models/test/test_exchange_main.py",
    "chars": 12305,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport time\n\nimport pytest\nfrom web"
  },
  {
    "path": "ocean_lib/models/test/test_factory_router.py",
    "chars": 2697,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\nfrom web3 import Web3"
  },
  {
    "path": "ocean_lib/models/test/test_fake_ocean.py",
    "chars": 1132,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport os\n\nimport pytest\nfrom eth_a"
  },
  {
    "path": "ocean_lib/models/ve/smart_wallet_checker.py",
    "chars": 231,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom ocean_lib.web3_internal.contra"
  },
  {
    "path": "ocean_lib/models/ve/test/conftest.py",
    "chars": 295,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\n\nfrom conftest_ganach"
  },
  {
    "path": "ocean_lib/models/ve/test/test_smart_wallet_checker.py",
    "chars": 266,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\n\n\n@pytest.mark.unit\nd"
  },
  {
    "path": "ocean_lib/models/ve/test/test_ve_allocate.py",
    "chars": 2720,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\nfrom web3.logs import"
  },
  {
    "path": "ocean_lib/models/ve/test/test_ve_delegation.py",
    "chars": 259,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\n\n\n@pytest.mark.unit\nd"
  },
  {
    "path": "ocean_lib/models/ve/test/test_ve_fee_distributor.py",
    "chars": 580,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\n\n\n@pytest.mark.unit\nd"
  },
  {
    "path": "ocean_lib/models/ve/test/test_ve_fee_estimate.py",
    "chars": 261,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\n\n\n@pytest.mark.unit\nd"
  },
  {
    "path": "ocean_lib/models/ve/test/test_ve_ocean.py",
    "chars": 2803,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport math\n\nimport pytest\n\nfrom oc"
  },
  {
    "path": "ocean_lib/models/ve/ve_allocate.py",
    "chars": 215,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom ocean_lib.web3_internal.contra"
  },
  {
    "path": "ocean_lib/models/ve/ve_delegation.py",
    "chars": 219,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom ocean_lib.web3_internal.contra"
  },
  {
    "path": "ocean_lib/models/ve/ve_fee_distributor.py",
    "chars": 227,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom ocean_lib.web3_internal.contra"
  },
  {
    "path": "ocean_lib/models/ve/ve_fee_estimate.py",
    "chars": 221,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom ocean_lib.web3_internal.contra"
  },
  {
    "path": "ocean_lib/models/ve/ve_ocean.py",
    "chars": 209,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom ocean_lib.web3_internal.contra"
  },
  {
    "path": "ocean_lib/ocean/__init__.py",
    "chars": 85,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n"
  },
  {
    "path": "ocean_lib/ocean/crypto.py",
    "chars": 2284,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\nfrom base64 import b64encode\nfrom "
  },
  {
    "path": "ocean_lib/ocean/mint_fake_ocean.py",
    "chars": 1336,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport os\n\nfrom enforce_typing impo"
  },
  {
    "path": "ocean_lib/ocean/ocean.py",
    "chars": 9282,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\n\"\"\"Ocean module.\"\"\"\nimport json\nim"
  },
  {
    "path": "ocean_lib/ocean/ocean_assets.py",
    "chars": 28269,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\n\"\"\"Ocean module.\"\"\"\nimport json\nim"
  },
  {
    "path": "ocean_lib/ocean/ocean_compute.py",
    "chars": 5672,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport logging\nfrom typing import A"
  },
  {
    "path": "ocean_lib/ocean/test/conftest.py",
    "chars": 31,
    "preview": "from conftest_ganache import *\n"
  },
  {
    "path": "ocean_lib/ocean/test/test_crypto.py",
    "chars": 1040,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom enforce_typing import enforce_"
  },
  {
    "path": "ocean_lib/ocean/test/test_ocean.py",
    "chars": 2512,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\n\nfrom ocean_lib.model"
  },
  {
    "path": "ocean_lib/ocean/test/test_ocean_assets.py",
    "chars": 20408,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport copy\nfrom datetime import da"
  },
  {
    "path": "ocean_lib/ocean/test/test_util.py",
    "chars": 1649,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\nimport pytest\nfrom web3 import Web"
  },
  {
    "path": "ocean_lib/ocean/util.py",
    "chars": 3223,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport hashlib\nfrom typing import O"
  },
  {
    "path": "ocean_lib/services/consumer_parameters.py",
    "chars": 2467,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\"\"\"\n    Consumer Parameters Class f"
  },
  {
    "path": "ocean_lib/services/service.py",
    "chars": 12069,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\"\"\"\n    Service Class for V4\n    To"
  },
  {
    "path": "ocean_lib/services/test/conftest.py",
    "chars": 31,
    "preview": "from conftest_ganache import *\n"
  },
  {
    "path": "ocean_lib/services/test/test_consumer_parameters.py",
    "chars": 1273,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\n\nfrom ocean_lib.servi"
  },
  {
    "path": "ocean_lib/services/test/test_service.py",
    "chars": 10870,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom unittest.mock import Mock, pat"
  },
  {
    "path": "ocean_lib/structures/abi_tuples.py",
    "chars": 1333,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\n\"\"\"Defines NamedTuples `Stakes`, `"
  },
  {
    "path": "ocean_lib/structures/algorithm_metadata.py",
    "chars": 2373,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport json\nfrom typing import Any,"
  },
  {
    "path": "ocean_lib/structures/file_objects.py",
    "chars": 3200,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom abc import abstractmethod\nfrom"
  },
  {
    "path": "ocean_lib/structures/test/test_algorithm_metadata.py",
    "chars": 1246,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport json\n\nimport pytest\n\nfrom oc"
  },
  {
    "path": "ocean_lib/structures/test/test_file_objects.py",
    "chars": 1414,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\n\nfrom ocean_lib.struc"
  },
  {
    "path": "ocean_lib/test/__init__.py",
    "chars": 85,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n"
  },
  {
    "path": "ocean_lib/test/test_config.py",
    "chars": 1433,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport json\n\nimport pytest\nfrom web"
  },
  {
    "path": "ocean_lib/test/test_example_config.py",
    "chars": 1355,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pytest\n\nfrom ocean_lib.examp"
  },
  {
    "path": "ocean_lib/web3_internal/__init__.py",
    "chars": 85,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n"
  },
  {
    "path": "ocean_lib/web3_internal/clef.py",
    "chars": 1288,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport sys\nfrom pathlib import Path"
  },
  {
    "path": "ocean_lib/web3_internal/constants.py",
    "chars": 290,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\n\"\"\"\nThis module holds following de"
  },
  {
    "path": "ocean_lib/web3_internal/contract_base.py",
    "chars": 6171,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\n\"\"\"All contracts inherit from `Con"
  },
  {
    "path": "ocean_lib/web3_internal/contract_utils.py",
    "chars": 3047,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport json\nimport logging\nimport o"
  },
  {
    "path": "ocean_lib/web3_internal/http_provider.py",
    "chars": 1444,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom web3 import HTTPProvider, Webs"
  },
  {
    "path": "ocean_lib/web3_internal/request.py",
    "chars": 1506,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\"\"\"\nThis is copied from Web3 python"
  },
  {
    "path": "ocean_lib/web3_internal/test/__init__.py",
    "chars": 85,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n"
  },
  {
    "path": "ocean_lib/web3_internal/test/conftest.py",
    "chars": 446,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\n# Directory ../ocean_lib/models/te"
  },
  {
    "path": "ocean_lib/web3_internal/test/test_contract_base.py",
    "chars": 1621,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\nimport pytest\n\nfrom ocean_lib.ocea"
  },
  {
    "path": "ocean_lib/web3_internal/test/test_contract_utils.py",
    "chars": 779,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom web3.main import Web3\n\nfrom oc"
  },
  {
    "path": "ocean_lib/web3_internal/test/test_wallet.py",
    "chars": 1113,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport os\n\nimport pytest\n\nfrom ocea"
  },
  {
    "path": "ocean_lib/web3_internal/utils.py",
    "chars": 2497,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport logging\nfrom collections imp"
  },
  {
    "path": "pyproject.toml",
    "chars": 45,
    "preview": "[tool.black]\nexclude = '''\n(\n  setup.py\n)\n'''"
  },
  {
    "path": "pytest.ini",
    "chars": 1430,
    "preview": "# pytest.ini\n[pytest]\nfilterwarnings =\n    ignore::DeprecationWarning\n    ignore:.*The event signature did not match the"
  },
  {
    "path": "requirements_dev.txt",
    "chars": 373,
    "preview": "# pip install ocean-lib\n# is for end users. That will install the packages\n# listed in the install_requires list of setu"
  },
  {
    "path": "setup.cfg",
    "chars": 442,
    "preview": "# Here is how we view setup.cfg vs setup.py: https://stackoverflow.com/a/46090408/14214722\n\n[bdist_wheel]\nuniversal = 1\n"
  },
  {
    "path": "setup.py",
    "chars": 2640,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Ap"
  },
  {
    "path": "tests/__init__.py",
    "chars": 85,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n"
  },
  {
    "path": "tests/flows/__init__.py",
    "chars": 85,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n"
  },
  {
    "path": "tests/flows/conftest.py",
    "chars": 31,
    "preview": "from conftest_ganache import *\n"
  },
  {
    "path": "tests/flows/test_start_reuse_order_fees.py",
    "chars": 18155,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nfrom datetime import datetime, time"
  },
  {
    "path": "tests/generated-readmes/__init__.py",
    "chars": 85,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n"
  },
  {
    "path": "tests/integration/ganache/conftest.py",
    "chars": 31,
    "preview": "from conftest_ganache import *\n"
  },
  {
    "path": "tests/integration/ganache/test_compute_flow.py",
    "chars": 19687,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport time\nfrom datetime import da"
  },
  {
    "path": "tests/integration/ganache/test_consume_flow.py",
    "chars": 3885,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport os\nimport shutil\n\nimport pyt"
  },
  {
    "path": "tests/integration/ganache/test_disconnecting_components.py",
    "chars": 2762,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport threading\nimport time\n\nimpor"
  },
  {
    "path": "tests/integration/ganache/test_graphql.py",
    "chars": 3044,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport json\nimport os\nimport shutil"
  },
  {
    "path": "tests/integration/ganache/test_market_flow.py",
    "chars": 4013,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\nimport os\n\nimport pytest\nfrom web3"
  },
  {
    "path": "tests/integration/ganache/test_onchain.py",
    "chars": 4497,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport os\nimport shutil\n\nimport pyt"
  },
  {
    "path": "tests/integration/remote/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/integration/remote/test_mumbai_main.py",
    "chars": 1301,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport os\n\nfrom ocean_lib.example_c"
  },
  {
    "path": "tests/integration/remote/test_mumbai_readme.py",
    "chars": 1153,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pathlib\nimport runpy\n\nfrom ."
  },
  {
    "path": "tests/integration/remote/test_polygon.py",
    "chars": 878,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport os\n\nimport pytest\n\nfrom ocea"
  },
  {
    "path": "tests/integration/remote/util.py",
    "chars": 5312,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport os\nimport random\nimport stri"
  },
  {
    "path": "tests/readmes/conftest.py",
    "chars": 31,
    "preview": "from conftest_ganache import *\n"
  },
  {
    "path": "tests/readmes/test_readmes.py",
    "chars": 1873,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport pathlib\nimport runpy\n\nimport"
  },
  {
    "path": "tests/resources/__init__.py",
    "chars": 85,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n"
  },
  {
    "path": "tests/resources/ddo/ddo_algorithm.json",
    "chars": 2677,
    "preview": "{\n  \"@context\": \"https://w3id.org/did/v1\",\n  \"created\": \"2019-02-08T08:13:49Z\",\n  \"id\": \"did:op:8d1b4d73e7af4634958f071a"
  },
  {
    "path": "tests/resources/ddo/ddo_algorithm2.json",
    "chars": 1712,
    "preview": "{\n  \"@context\": [\"https://w3id.org/did/v1\"],\n  \"id\": \"did:op:ACce67694eD2848dd683c651Dab7Af823b7dd123\",\n  \"version\": \"4."
  },
  {
    "path": "tests/resources/ddo/ddo_sa_sample.json",
    "chars": 4297,
    "preview": "{\n  \"@context\": \"https://w3id.org/did/v1\",\n  \"created\": \"2019-02-08T08:13:49Z\",\n  \"updated\": \"2019-03-08T08:13:49Z\",\n  \""
  },
  {
    "path": "tests/resources/ddo/ddo_sa_sample_disabled.json",
    "chars": 4365,
    "preview": "{\n  \"@context\": \"https://w3id.org/did/v1\",\n  \"created\": \"2019-02-08T08:13:49Z\",\n  \"updated\": \"2019-03-08T08:13:49Z\",\n  \""
  },
  {
    "path": "tests/resources/ddo/ddo_sa_sample_with_credentials.json",
    "chars": 4481,
    "preview": "{\n  \"@context\": \"https://w3id.org/did/v1\",\n  \"created\": \"2019-02-08T08:13:49Z\",\n  \"updated\": \"2019-03-08T08:13:49Z\",\n  \""
  },
  {
    "path": "tests/resources/ddo/ddo_sample_algorithm.json",
    "chars": 2677,
    "preview": "{\n  \"@context\": \"https://w3id.org/did/v1\",\n  \"created\": \"2019-02-08T08:13:49Z\",\n  \"id\": \"did:op:8d1b4d73e7af4634958f071a"
  },
  {
    "path": "tests/resources/ddo/ddo_v4_sample.json",
    "chars": 1687,
    "preview": "{\n  \"@context\": [\"https://w3id.org/did/v1\"],\n  \"id\": \"did:op:d32696f71f3318c92bcf325e2e51e6e8299c0eb6d362ddcfa77d2a3e0c1"
  },
  {
    "path": "tests/resources/ddo/ddo_v4_with_compute_service.json",
    "chars": 2736,
    "preview": "{\n  \"@context\": [\"https://w3id.org/did/v1\"],\n  \"id\": \"did:op:d32696f71f3318c92bcf325e2e51e6e8299c0eb6d362ddcfa77d2a3e0c1"
  },
  {
    "path": "tests/resources/ddo/ddo_v4_with_compute_service2.json",
    "chars": 2708,
    "preview": "{\n  \"@context\": [\"https://w3id.org/did/v1\"],\n  \"id\": \"did:op:d32696f71f3318c92bcf325e2e51e6e8299c0eb6d362ddcfa77d2a3e0c1"
  },
  {
    "path": "tests/resources/ddo/ddo_with_compute_service.json",
    "chars": 3295,
    "preview": "{\n  \"@context\": \"https://w3id.org/future-method/v1\",\n  \"created\": \"2019-04-09T19:02:11Z\",\n  \"id\": \"did:op:8d1b4d73e7af46"
  },
  {
    "path": "tests/resources/ddo/valid_metadata.json",
    "chars": 1027,
    "preview": "{\n  \"main\": {\n    \"name\": \"10 Monkey Species Small\",\n    \"dateCreated\": \"2012-02-01T10:55:11Z\",\n    \"author\": \"Mario\",\n "
  },
  {
    "path": "tests/resources/ddo_helpers.py",
    "chars": 3958,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport json\nimport os\nimport pathli"
  },
  {
    "path": "tests/resources/helper_functions.py",
    "chars": 11071,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport json\nimport logging\nimport l"
  },
  {
    "path": "tests/resources/keys/key_file_1.json",
    "chars": 635,
    "preview": "{\n  \"id\": \"50aa801a-8d66-1402-1fa4-d8987868c2ce\",\n  \"version\": 3,\n  \"crypto\": {\n    \"cipher\": \"aes-128-ctr\",\n    \"cipher"
  },
  {
    "path": "tests/resources/keys/key_file_2.json",
    "chars": 645,
    "preview": "{\n  \"id\": \"0902d04b-f26e-5c1f-e3ae-78d2c1cb16e7\",\n  \"version\": 3,\n  \"crypto\": {\n    \"cipher\": \"aes-128-ctr\",\n    \"cipher"
  },
  {
    "path": "tests/resources/mocks/__init__.py",
    "chars": 85,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n"
  },
  {
    "path": "tests/resources/mocks/data_provider_mock.py",
    "chars": 1723,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\n\nimport os\n\nfrom ocean_lib.data_pro"
  },
  {
    "path": "tests/resources/mocks/http_client_mock.py",
    "chars": 3775,
    "preview": "#\n# Copyright 2023 Ocean Protocol Foundation\n# SPDX-License-Identifier: Apache-2.0\n#\nimport inspect\nimport json\nfrom uni"
  },
  {
    "path": "tests/resources/test/test_helper_functions.py",
    "chars": 552,
    "preview": "from tests.resources.helper_functions import convert_bt_amt_to_dt\n\n\ndef test_convert_bt_amt_to_dt():\n    bt_decimals = 1"
  }
]

About this extraction

This page contains the full source code of the oceanprotocol/ocean.py GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 195 files (662.9 KB), approximately 168.9k tokens, and a symbol index with 656 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!