diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1902cd7..4cc07b5b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,7 +3,8 @@ name: 'CI' on: push: branches: - - '**' + - main + - v4 pull_request: branches: - '**' diff --git a/.gitignore b/.gitignore index 9e696fd5..47066e69 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ yarn-error.log .env.* markdowns/ .vscode/ -size-plugin.json \ No newline at end of file +size-plugin.json +read-the-docs/ \ No newline at end of file diff --git a/.markdownlint.json b/.markdownlint.json index 6c7ee37e..c5d00817 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -11,5 +11,6 @@ "no-trailing-punctuation": false, "ol-prefix": false, "ul-style": { "style": "dash" }, - "no-emphasis-as-header": false + "no-emphasis-as-header": false, + "blanks-around-fences": false } diff --git a/config.js b/config.js index 2e006ba7..25c602b1 100644 --- a/config.js +++ b/config.js @@ -42,7 +42,7 @@ module.exports = { }, { from: '/setup/compute-to-data/', - to: '/tutorials/compute-to-data/' + to: '/tutorials/compute-to-data-minikube/' }, { from: '/concepts/networks-overview/', @@ -92,7 +92,7 @@ module.exports = { swaggerComponents: [ { name: 'aquarius', - url: 'https://aquarius.oceanprotocol.com/spec' + url: 'https://v4.aquarius.oceanprotocol.com/spec' }, { name: 'provider', diff --git a/content/concepts/architecture.md b/content/concepts/architecture.md index 8d2e6976..e1d4437b 100644 --- a/content/concepts/architecture.md +++ b/content/concepts/architecture.md @@ -1,6 +1,6 @@ --- title: Architecture Overview -description: Simplicity and Interoperability via a Datatokens Core +description: Data NFTs and datatokens architecture --- ## Overview @@ -11,27 +11,31 @@ Here is the Ocean architecture. Here’s an overview of the figure. -- The top layer is **applications** like Ocean Market. With these apps, users can onboard data services into crypto (publish and mint datatokens), hold datatokens as assets (data wallets), discover data assets and buy / sell datatokens for fixed or auto-determined price (data marketplaces), and consume data services (consume datatokens). -- Below that are **libraries** used by the applications: Ocean React hooks, JavaScript library, and Python library. This also includes middleware to assist discovery: Aquarius and (3rd party tool) TheGraph. -- The lowest level has the **smart contracts** used by the libraries. They’re deployed on Ethereum mainnet to start, and other networks later. +- The top layer is **applications** like Ocean Market. With these apps, users can onboard services like data, algorithms, compute-to-data into crypto (publish and mint data NFTs and datatokens), hold datatokens as assets (data wallets), discover assets, and buy/sell datatokens for a fixed or auto-determined price (data marketplaces), and consume data services (consume datatokens). +- Below are **libraries** used by the applications: Ocean.js (JavaScript library) and Ocean.py (Python library). This also includes middleware to assist discovery: + - **Aquarius**: Provides metadata cache for faster search by caching on-chain data into elasticsearch + - **Provider**: Facilitates downloading assets, DDO encryption, and communicating with `operator-service` for Compute-to-Data jobs. + - **The Graph**: It is a 3rd party tool that developers can utilize the libraries to build their custom applications and marketplaces. +- The lowest level has the **smart contracts**. The smart contracts are deployed on the Ethereum mainnet and other compatible networks. Libraries encapsulate the calls to these smart contracts and provide features like publishing new assets, facilitating consumption, managing pricing, and much more. To see the supported networks click [here](/concepts/networks/). -Left to right are groupings of functionality: tools for datatokens, tools for markets (including pools), tools to consume data services and for metadata, and external ERC20 tools. +## Data NFTs, Datatokens and Access Control Tools -The rest of this page elaborates. +Data NFTs are based on [ERC721](https://eips.ethereum.org/EIPS/eip-721) standard. The publisher can use Marketplace or client libraries to deploy a new data NFT contract. To save gas fees, it uses [ERC1167](https://eips.ethereum.org/EIPS/eip-1167) proxy approach on the **ERC721 template**. Publisher can then assign manager role to other Ethereum addresses who can deploy new datatoken contracts and even mint them. Each datatoken contract is associated with one data NFT contract. +Click [here](/concepts/datanft-and-datatoken/) to further read about data NFTs and datatokens. -## Datatokens & Access Control Tools +ERC721 data NFTs represent holding copyright/base IP of a data asset, and ERC20 datatokens represent licenses to consume the data asset. -The publisher actor holds the dataset in Google Drive, Dropbox, AWS S3, on their phone, on their home server, etc. The dataset has a URL. The publisher can optionally use IPFS for a content-addressable URL. Or instead of a file, the publisher may run a compute-to-data service. +Datatoken represents the asset that the publisher wants to monetize. The asset can be a dataset or an algorithm. The publisher actor holds the asset in Google Drive, Dropbox, AWS S3, on their phone, on their home server, etc. The publisher can optionally use IPFS for a content-addressable URL. Or instead of a file, the publisher may run a compute-to-data service. In the **publish** step, the publisher invokes **Ocean Datatoken Factory** to deploy a new datatoken to the chain. To save gas fees, it uses [ERC1167](https://eips.ethereum.org/EIPS/eip-1167) proxy approach on the **ERC20 datatoken template**. The publisher then mints datatokens. -The publisher runs **Ocean Provider**. In the **consume** step, Provider software needs to retrieve the data service URL given a datatoken address. One approach would be for the publisher to run a database; however this adds another dependency. To avoid this, it stores the URL on-chain. So that others don’t see that URL, it encrypts it. +The publisher runs their own **Ocean Provider** or can use one deployed by Ocean Protocol. In the **consume** step, Provider software needs to retrieve the data service URL given a datatoken address. One approach would be for the publisher to run a database. However, this adds another dependency. To avoid this, the Provider encrypts the URL and it URL on-chain. To initiate the **consume** step, the data consumer sends 1.0 datatokens to the Provider wallet. Then they make a service request to the Provider. The Provider loads the encrypted URL, decrypts it, and provisions the requested service (send static data, or enable a compute-to-data job). -Instead of running a Provider themselves, the publisher can have a 3rd party like Ocean Market run it. While more convenient, it means that the 3rd party has custody of the private encryption/decryption key (more centralized). Ocean will support more service types and url custody options in the future. +Instead of running a Provider themselves, the publisher can have a 3rd party like Ocean Market to run it. While more convenient, it means that the 3rd party has custody of the private encryption/decryption key (more centralized). Ocean will support more service types and URL custody options in the future. -**Ocean JavaScript and Python libraries** act as drivers for the lower-level contracts. Each library integrates with Ocean Provider to provision & consume data services, and Ocean Aquarius for metadata. **Ocean React hooks** use the JavaScript library, to help build web apps & React Native apps with Ocean. +**Ocean JavaScript and Python libraries** act as drivers for the lower-level contracts. Each library integrates with Ocean Provider to provision & consume data services, and Ocean Aquarius for metadata. @@ -45,8 +49,8 @@ The marketplaces are decentralized (no single owner or controller), and non-cust Ocean Market supports fixed pricing and automatic price discovery. -- For **fixed pricing**, there’s a simple contract for users to buy/sell datatokens for OCEAN, while avoiding custodianship during value transfer. -- For **automatic price discovery**, Ocean Market uses automated market makers (AMMs) powered by [Balancer](https://www.balancer.finance). Each pool is a datatoken-OCEAN pair. In the Ocean Market GUI, the user adds liquidity then invokes pool creation; the GUI’s React code calls the Ocean JavaScript library, which calls the **Pool Factory** to deploy a **Pool** contract. (The Python library also does this.) Deploying a datatoken pool can be viewed as an “Initial Data Offering” (IDO). +- For **fixed pricing**, there’s a simple contract for users to buy/sell datatokens for OCEAN while avoiding custodianship during value transfer. +- For **automatic price discovery**, Ocean Market uses automated market makers (AMMs) powered by [Balancer](https://www.balancer.fi). Each pool is a datatoken-OCEAN pair. In the Ocean Market GUI, the user adds liquidity then invokes pool creation; the GUI’s React code calls the Ocean JavaScript library, which calls the **Pool Factory** to deploy a **Pool** contract. (The Python library also does this.) Deploying a datatoken pool can be viewed as an “Initial Data Offering” (IDO). Complementary to Ocean Market, Ocean has reference code to ease building **third-party data marketplaces**, such as for logistics ([dexFreight data marketplace](https://blog.oceanprotocol.com/dexfreight-ocean-protocol-partner-to-enable-transportation-logistics-companies-to-monetize-data-7aa839195ac)) or mobility ([Daimler](https://blog.oceanprotocol.com/ocean-protocol-delivers-proof-of-concept-for-daimler-ag-in-collaboration-with-daimler-south-east-564aa7d959ca)). @@ -56,14 +60,14 @@ Complementary to Ocean Market, Ocean has reference code to ease building **third ## Metadata Tools -Metadata (name of dataset, date created etc.) is used by marketplaces for data asset discovery. Each data asset can have a [decentralized identifier](https://w3c-ccg.github.io/did-spec/) (DID) that resolves to a DID document (DDO) for associated metadata. The DDO is essentially [JSON](https://www.json.org/) filling in metadata fields. For more details on working with OCEAN DIDs check out the [DID concept documentation](https://docs.oceanprotocol.com/concepts/did-ddo/). +Marketplaces use the Metadata of the asset for discovery. Metadata consists of information like the type of asset, name of the asset, creation date, license, etc. Each data asset can have a [decentralized identifier](https://w3c-ccg.github.io/did-spec/) (DID) that resolves to a DID document (DDO) for associated metadata. The DDO is essentially [JSON](https://www.json.org/) filling in metadata fields. For more details on working with OCEAN DIDs check out the [DID concept documentation](https://docs.oceanprotocol.com/concepts/did-ddo/). The [DDO Metadata documentation](https://docs.oceanprotocol.com/concepts/ddo-metadata/) goes into more depth regarding metadata structure. -[OEP8](https://github.com/oceanprotocol/OEPs/tree/master/8) specifies Ocean metadata schema, including fields that must be filled. It’s based on the public [DataSet schema from schema.org](https://schema.org/Dataset). +[OEP8](/concepts/did-ddo/) specifies Ocean metadata schema, including fields that must be filled. It’s based on the public [DataSet schema from schema.org](https://schema.org/Dataset). -Ocean uses the Ethereum mainnet as an **on-chain metadata store**, i.e. to store both DID and DDO. This means that once the write fee is paid, there are no further expenses or dev-ops work needed to ensure metadata availability into the future, aiding in the discoverability of data assets. It also simplifies integration with the rest of the Ocean system, which is Ethereum-based. Storage cost on Ethereum mainnet is not negligible, but not prohibitive and the other benefits are currently worth the tradeoff compared to alternatives. +Ocean uses the Ethereum mainnet and other compatible networks as an **on-chain metadata store**, i.e. to store both DID and DDO. This means that once the transaction fee is paid, there are no further expenses or devops work needed to ensure metadata availability into the future, aiding in the discoverability of data assets. It also simplifies integration with the rest of the Ocean system, which is Ethereum-based. Storage cost on Ethereum mainnet is not negligible, but not prohibitive and the other benefits are currently worth the trade-off compared to alternatives. -Due to the permissionless, decentralized nature of data on Ethereum mainnet, any last-mile tool can access metadata. **Ocean Aquarius** supports different metadata fields for each different Ocean-based marketplace. Developers could also use [TheGraph](https://www.thegraph.com) to see metadata fields that are common across all marketplaces. +Due to the permissionless, decentralized nature of data on the Ethereum mainnet, any last mile tool can access metadata. **Ocean Aquarius** supports different metadata fields for each different Ocean-based marketplace. Developers could also use [The Graph](https://www.thegraph.com) to see metadata fields that are common across all marketplaces. diff --git a/content/concepts/compute-to-data.md b/content/concepts/compute-to-data.md index da470041..623ef380 100644 --- a/content/concepts/compute-to-data.md +++ b/content/concepts/compute-to-data.md @@ -24,7 +24,7 @@ The most basic scenario for a Publisher is to provide access to the datasets the - [Compute-to-Data architecture](/tutorials/compute-to-data-architecture/) - [Tutorial: Writing Algorithms](/tutorials/compute-to-data-algorithms/) -- [Tutorial: Set Up a Compute-to-Data Environment](/tutorials/compute-to-data/) +- [Tutorial: Set Up a Compute-to-Data Environment](/tutorials/compute-to-data-minikube/) - [Use Compute-to-Data in Ocean Market](https://blog.oceanprotocol.com/compute-to-data-is-now-available-in-ocean-market-58868be52ef7) - [Build ML models via Ocean Market or Python](https://medium.com/ravenprotocol/machine-learning-series-using-logistic-regression-for-classification-in-oceans-compute-to-data-18df49b6b165) - [Compute-to-Data Python Quickstart](https://github.com/oceanprotocol/ocean.py/blob/main/READMEs/c2d-flow.md) diff --git a/content/concepts/datanft-and-datatoken.md b/content/concepts/datanft-and-datatoken.md new file mode 100644 index 00000000..7dce5d01 --- /dev/null +++ b/content/concepts/datanft-and-datatoken.md @@ -0,0 +1,48 @@ +--- +title: Data NFTs and Datatokens +description: In Ocean Protocol, ERC721 data NFTs represent holding copyright/base IP of a data asset, and ERC20 datatokens represent licenses to consume the assets. +--- + +A non-fungible token stored on the blockchain represents a unique asset. NFTs can represent images, videos, digital art, or any piece of information. NFTs can be traded, and allow transfer of copyright/base IP. [EIP-721](https://eips.ethereum.org/EIPS/eip-721) defines an interface for handling NFTs on EVM-compatible blockchains. The creator of the NFT can deploy a new contract on Ethereum or any Blockchain supporting NFT related interface and also, transfer the ownership of copyright/base IP through transfer transactions. + +Fungible tokens represent fungible assets. If you have 5 ETH and Alice has 5 ETH, you and Alice could swap your ETH and your final holdings remain the same. They're apples-to-apples. Licenses (contracts) to consume a copyrighted asset are naturally fungible - they can be swapped with each other. + +![Data NFT and datatoken](images/datanft-and-datatoken.png) + +## High-Level Architecture + +The image above describes how ERC721 data NFTs, ERC20 datatokens, and AMMs relate. + +- Bottom: The publisher deploys an ERC721 data NFT contract representing the base IP for the data asset. They are now the manager of the data NFT. +- Middle: The manager then deploys an ERC20 datatoken contract against the data NFT. The ERC20 represents a license with specific terms like "can consume for the next 3 days". They could even publish further ERC20 datatoken contracts, to represent different license terms or for compute-to-data. +- Top: The manager then deploys a pool of the datatoken and OCEAN (or H2O), adds initial liquidity, and receives ERC20 pool tokens in return. Others may also add liquidity to receive pool tokens, i.e. become liquidity providers (LPs). + +## Terminology + +- **Base IP** means the artifact being copyrighted. Represented by the {ERC721 address, tokenId} from the publish transactions. +- **Base IP holder** means the holder of the Base IP. Represented as the actor that did the initial "publish" action. +- **Sub-licensee** is the holder of the sub-license. Represented as the entity that controls address ERC721.\_owners[tokenId=x]. +- **To Publish**: Claim copyright or exclusive base license. +- **To Sub-license**: Transfer one (of many) sub-licenses to new licensee: ERC20.transfer(to=licensee, value=1.0). + +## Implementation in Ocean Protocol + +Ocean Protocol defines the [ERC721Factory](https://github.com/oceanprotocol/contracts/blob/v4main/contracts/ERC721Factory.sol) contract, allowing **Base IP holders** to create their ERC721 contract instances on any supported networks. The deployed contract stores Metadata, ownership, sub-license information, permissions. The contract creator can also create and mint ERC20 token instances for sub-licensing the **Base IP**. + +ERC721 tokens are non-fungible, thus cannot be used for automatic price discovery like ERC20 tokens. ERC721 and ERC20 combined together can be used for sub-licensing. Ocean Protocol's [ERC721Template](https://github.com/oceanprotocol/contracts/blob/v4main/contracts/templates/ERC721Template.sol) solves this problem by using ERC721 for tokenizing the **Base IP** and tokenizing sub-licenses by using ERC20. Thus, sub-licenses can be traded on any AMM as the underlying contract is ERC20 compliant. + +## High-Level Behavior + +![Flow](images/use-case.png) + +Here's an example. + +- In step 1, Alice **publishes** her dataset with Ocean: this means deploying an ERC721 data NFT contract (claiming copyright/base IP), then an ERC20 datatoken contract (license against base IP). +- In step 2, she **mints** some ERC20 datatokens and **transfers** 1.0 of them to Bob's wallet; now he has a license to be able to consume that dataset. + +## Other References + +- [Data & NFTs 1: Practical Connections of ERC721 with Intellectual Property](https://blog.oceanprotocol.com/nfts-ip-1-practical-connections-of-erc721-with-intellectual-property-dc216aaf005d) +- [Data & NFTs 2: Leveraging ERC20 Fungibility](https://blog.oceanprotocol.com/nfts-ip-2-leveraging-erc20-fungibility-bcee162290e3) +- [Data & NFTs 3: Combining ERC721 & ERC20](https://blog.oceanprotocol.com/nfts-ip-3-combining-erc721-erc20-b69ea659115e) +- [Fungibility sightings in NFTs](https://blog.oceanprotocol.com/on-difficult-to-explain-fungibility-sightings-in-nfts-26bc18620f70) diff --git a/content/concepts/ddo-metadata.md b/content/concepts/ddo-metadata.md deleted file mode 100644 index 94dfb94f..00000000 --- a/content/concepts/ddo-metadata.md +++ /dev/null @@ -1,349 +0,0 @@ ---- -title: DDO Metadata -description: Specification of the DDO subset dedicated to asset metadata -slug: /concepts/ddo-metadata/ -section: concepts ---- - -## Overview - -This page defines the schema for asset _metadata_. Metadata is the subset of an Ocean DDO that holds information about the asset. - -The schema is based on public schema.org [DataSet schema](https://schema.org/Dataset). - -Standardizing labels is key to effective searching, sorting and filtering (discovery). - -This page specifies metadata attributes that _must_ be included, and that _may_ be included. These attributes are organized hierarchically, from top-layer attributes like `"main"` to sub-level attributes like `"main.type"`. This page also provides DDO metadata examples. - -## Rules for Metadata Storage and Control in Ocean - -The publisher publishes an asset DDO (including metadata) onto the chain. - -The publisher may be the asset owner, or a marketplace acting on behalf of the owner. - -Most metadata fields may be modified after creation. The blockchain records the provenance of changes. - -DDOs (including metadata) are found in two places: - -- _Remote_ - main storage, on-chain. File URLs are always encrypted. One may actually encrypt all metadata, at a severe cost to discoverability. -- _Local_ - local cache. All fields are in plaintext. - -Ocean Aquarius helps manage metadata. It can be used to write DDOs to the chain, read from the chain, and has a local cache of the DDO in plaintext with fast search. - -## Fields for Metadata - -An asset represents a resource in Ocean, e.g. a dataset or an algorithm. - -A `metadata` object has the following attributes, all of which are objects. Some are only required for local or remote, and are specified as such. - -| Attribute | Required | Description | -| --------------------------- | -------- | ---------------------------------------------------------- | -| **`main`** | **Yes** | Main attributes | -| **`encryptedFiles`** | Remote | Encrypted string of the `attributes.main.files` object. | -| **`encryptedServices`** | Remote | Encrypted string of the `attributes.main.services` object. | -| **`status`** | No | Status attributes | -| **`additionalInformation`** | No | Optional attributes | - -The `main` and `additionalInformation` attributes are independent of the asset type. - -## Fields for `attributes.main` - -The `main` object has the following attributes. - -| Attribute | Type | Required | Description | -| ------------------- | --------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **`name`** | Text |**Yes** | Descriptive name or title of the asset. | -| **`type`** | Text |**Yes** | Asset type. Includes `"dataset"` (e.g. csv file), `"algorithm"` (e.g. Python script). Each type needs a different subset of metadata attributes. | -| **`author`** | Text |**Yes** | Name of the entity generating this data (e.g. Tfl, Disney Corp, etc.). | -| **`license`** | Text |**Yes** | Short name referencing the license of the asset (e.g. Public Domain, CC-0, CC-BY, No License Specified, etc. ). If it's not specified, the following value will be added: "No License Specified". | -| **`files`** | Array of files object |**Yes** | Array of `File` objects including the encrypted file urls. | -| **`dateCreated`** | DateTime |**Yes** | The date on which the asset was created by the originator. ISO 8601 format, Coordinated Universal Time, e.g. `2019-01-31T08:38:32Z`. | -| **`datePublished`** | DateTime | Remote | The date on which the asset DDO is registered into the metadata store (Aquarius) | - -## Fields for `attributes.main.files` - -The `files` object has a list of `file` objects. - -Each `file` object has the following attributes, with the details necessary to consume and validate the data. - -| Attribute | Required | Description | -| -------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **`index`** |**Yes** | Index number starting from 0 of the file. | -| **`contentType`** |**Yes** | File format. | -| **`url`** | Local | Content URL. Omitted from the remote metadata. Supports `http(s)://` and `ipfs://` URLs. | -| **`name`** | No | File name. | -| **`checksum`** | No | Checksum of the file using your preferred format (i.e. MD5). Format specified in `checksumType`. If it's not provided can't be validated if the file was not modified after registering. | -| **`checksumType`** | No | Format of the provided checksum. Can vary according to server (i.e Amazon vs. Azure) | -| **`contentLength`** | No | Size of the file in bytes. | -| **`encoding`** | No | File encoding (e.g. UTF-8). | -| **`compression`** | No | File compression (e.g. no, gzip, bzip2, etc). | -| **`encrypted`** | No | Boolean. Is the file encrypted? If is not set is assumed the file is not encrypted | -| **`encryptionMode`** | No | Encryption mode used. Just valid if `encrypted=true` | -| **`resourceId`** | No | Remote identifier of the file in the external provider. It is typically the remote id in the cloud provider. | -| **`attributes`** | No | Key-Value hash map with additional attributes describing the asset file. It could include details like the Amazon S3 bucket, region, etc. | - -## Fields for `attributes.status` - -A `status` object has the following attributes. - -| Attribute | Type | Required | Description | -| --------------------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **`isListed`** | Boolean | No | Use to flag unsuitable content. True by default. If it's false, the content must not be returned. | -| **`isRetired`** | Boolean | No | Flag retired content. False by default. If it's true, the content may either not be returned, or returned with a note about retirement. | -| **`isOrderDisabled`** | Boolean | No | For temporarily disabling ordering assets, e.g. when file host is in maintenance. False by default. If it's true, no ordering of assets for download or compute should be allowed. | - -## Fields for `attributes.additionalInformation` - -All the additional information will be stored as part of the `additionalInformation` section. - -| Attribute | Type | Required | -| --------------------- | ------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **`tags`** | Array of Text | No | Array of keywords or tags used to describe this content. Empty by default. | -| **`description`** | Text | No | Details of what the resource is. For a dataset, this attribute explains what the data represents and what it can be used for. | -| **`copyrightHolder`** | Text | No | The party holding the legal copyright. Empty by default. | -| **`workExample`** | Text | No | Example of the concept of this asset. This example is part of the metadata, not an external link. | -| **`links`** | Array of Link | No | Mapping of links for data samples, or links to find out more information. Links may be to either a URL or another Asset. We expect marketplaces to converge on agreements of typical formats for linked data: The Ocean Protocol itself does not mandate any specific formats as these requirements are likely to be domain-specific. The links array can be an empty array, but if there is a link object in it, then an "url" is required in that link object. | -| **`inLanguage`** | Text | No | The language of the content. Please use one of the language codes from the [IETF BCP 47 standard](https://tools.ietf.org/html/bcp47). | -| **`categories`** | Array of Text | No | Optional array of categories associated to the asset. Note: recommended to use `"tags"` instead of this. | - -## Fields - Other Suggestions - -Here are example attributes to help an asset's discoverability. - -| Attribute | Description | -| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **`updateFrequency`** | An indication of update latency - i.e. How often are updates expected (seldom, annually, quarterly, etc.), or is the resource static that is never expected to get updated. | -| **`structuredMarkup`** | A link to machine-readable structured markup (such as ttl/json-ld/rdf) describing the dataset. | - -## DDO Metadata Example - Local - -This is what the DDO metadata looks like. All fields are in plaintext. This is before it's stored on-chain or when it's retrieved and decrypted into a local cache. - -```json -{ - "main": { - "name": "Madrid Weather forecast", - "dateCreated": "2019-05-16T12:36:14.535Z", - "author": "Norwegian Meteorological Institute", - "type": "dataset", - "license": "Public Domain", - "price": "123000000000000000000", - "files": [ - { - "index": 0, - "url": "https://example-url.net/weather/forecast/madrid/350750305731.xml", - "contentLength": "0", - "contentType": "text/xml", - "compression": "none" - } - ] - }, - "additionalInformation": { - "description": "Weather forecast of Europe/Madrid in XML format", - "copyrightHolder": "Norwegian Meteorological Institute", - "categories": ["Other"], - "links": [], - "tags": [], - "updateFrequency": null, - "structuredMarkup": [] - }, - "status": { - "isListed": true, - "isRetired": false, - "isOrderDisabled": false - } -} -``` - -## DDO Metadata Example - Remote - -The previous example was for a local cache, with all fields in plaintext. - -Here's the same example, for remote on-chain storage. That is, it's how metadata looks as a response to querying Aquarius (remote metadata). - -How remote is changed, compared to local: - -- `url` is removed from all objects in the `files` array -- `encryptedFiles` is added. - -```json -{ - "service": [ - { - "index": 0, - "serviceEndpoint": "http://aquarius:5000/api/v1/aquarius/assets/ddo/{did}", - "type": "metadata", - "attributes": { - "main": { - "type": "dataset", - "name": "Madrid Weather forecast", - "dateCreated": "2019-05-16T12:36:14.535Z", - "author": "Norwegian Meteorological Institute", - "license": "Public Domain", - "files": [ - { - "contentLength": "0", - "contentType": "text/xml", - "compression": "none", - "index": 0 - } - ], - "datePublished": "2019-05-16T12:41:01Z" - }, - "encryptedFiles": "0x7a0d1c66ae861…df43aa9", - "additionalInformation": { - "description": "Weather forecast of Europe/Madrid in XML format", - "copyrightHolder": "Norwegian Meteorological Institute", - "categories": ["Other"], - "links": [], - "tags": [], - "updateFrequency": null, - "structuredMarkup": [] - }, - "status": { - "isListed": true, - "isRetired": false, - "isOrderDisabled": false - } - } - } - ] -} -``` - -## Fields when `attributes.main.type = algorithm` - -An asset of type `algorithm` has the following additional attributes under `main.algorithm`: - -| Attribute | Type | Required | Description | -| --------------- | -------- | -------- | --------------------------------------------- | -| **`container`** | `Object` |**Yes** | Object describing the Docker container image. | -| **`language`** | `string` | No | Language used to implement the software | -| **`format`** | `string` | No | Packaging format of the software. | -| **`version`** | `string` | No | Version of the software. | - -The `container` object has the following attributes: - -| Attribute | Type | Required | Description | -| ---------------- | -------- | -------- | ----------------------------------------------------------------- | -| **`entrypoint`** | `string` |**Yes** | The command to execute, or script to run inside the Docker image. | -| **`image`** | `string` |**Yes** | Name of the Docker image. | -| **`tag`** | `string` |**Yes** | Tag of the Docker image. | -| **`checksum`** | `string` |**Yes** | Checksum of the Docker image. | - -```json -{ - "index": 0, - "serviceEndpoint": "http://localhost:5000/api/v1/aquarius/assets/ddo/{did}", - "type": "metadata", - "attributes": { - "main": { - "author": "John Doe", - "dateCreated": "2019-02-08T08:13:49Z", - "license": "CC-BY", - "name": "My super algorithm", - "type": "algorithm", - "algorithm": { - "language": "scala", - "format": "docker-image", - "version": "0.1", - "container": { - "entrypoint": "node $ALGO", - "image": "node", - "tag": "10", - "checksum": "efb2c764274b745f5fc37f97c6b0e761" - } - }, - "files": [ - { - "name": "build_model", - "url": "https://raw.gith ubusercontent.com/oceanprotocol/test-algorithm/master/javascript/algo.js", - "index": 0, - "checksum": "efb2c764274b745f5fc37f97c6b0e761", - "contentLength": "4535431", - "contentType": "text/plain", - "encoding": "UTF-8", - "compression": "zip" - } - ] - }, - "additionalInformation": { - "description": "Workflow to aggregate weather information", - "tags": ["weather", "uk", "2011", "workflow", "aggregation"], - "copyrightHolder": "John Doe" - } - } -} -``` - -## Fields when `attributes.main.type = compute` - -An asset with a service of type `compute` has the following additional attributes under `main.privacy`: - -| Attribute | Type | Required | Description | -| --------------------------------- | ------------------ | -------- | ---------------------------------------------------------- | -| **`allowRawAlgorithm`** | `boolean` |**Yes** | If True, a drag & drop algo can be runned | -| **`allowNetworkAccess`** | `boolean` |**Yes** | If True, the algo job will have network access (stil WIP) | -| **`publisherTrustedAlgorithms `** | Array of `Objects` |**Yes** | If Empty , then any published algo is allowed. (see below) | - -The `publisherTrustedAlgorithms ` is an array of objects with the following structure: - -| Attribute | Type | Required | Description | -| ------------------------------ | -------- | -------- | ------------------------------------------------------------------ | -| **`did`** | `string` |**Yes** | The did of the algo which is trusted by the publisher. | -| **`filesChecksum`** | `string` |**Yes** | Hash of ( algorithm's encryptedFiles + files section (as string) ) | -| **`containerSectionChecksum`** | `string` |**Yes** | Hash of the algorithm container section (as string) | - -To produce `filesChecksum`: - -```javascript -sha256( - algorithm_ddo.service['metadata'].attributes.encryptedFiles + - JSON.Stringify(algorithm_ddo.service['metadata'].attributes.main.files) -) -``` - -To produce `containerSectionChecksum`: - -```javascript -sha256( - JSON.Stringify( - algorithm_ddo.service['metadata'].attributes.main.algorithm.container - ) -) -``` - -### Example of a compute service - -```json -{ - "type": "compute", - "index": 1, - "serviceEndpoint": "https://provider.oceanprotocol.com", - "attributes": { - "main": { - "name": "dataAssetComputingService", - "creator": "0xA32C84D2B44C041F3a56afC07a33f8AC5BF1A071", - "datePublished": "2021-02-17T06:31:33Z", - "cost": "1", - "timeout": 3600, - "privacy": { - "allowRawAlgorithm": true, - "allowNetworkAccess": false, - "publisherTrustedAlgorithms": [ - { - "did": "0xxxxx", - "filesChecksum": "1234", - "containerSectionChecksum": "7676" - }, - { - "did": "0xxxxx", - "filesChecksum": "1232334", - "containerSectionChecksum": "98787" - } - ] - } - } - } -} -``` diff --git a/content/concepts/did-ddo.md b/content/concepts/did-ddo.md index ead82a63..ef1d97b9 100644 --- a/content/concepts/did-ddo.md +++ b/content/concepts/did-ddo.md @@ -1,173 +1,879 @@ --- -title: DIDs & DDOs - Asset Identifiers & Objects -description: Specification of Ocean asset identifiers and objects using DIDs & DDOs +title: DID & DDO +description: Specification of decentralized identifiers for assets in Ocean Protocol using the DID & DDO standards. slug: /concepts/did-ddo/ section: concepts --- +**v4.0.0** + ## Overview -This document describes how Ocean assets follow the DID/DDO spec, such that Ocean assets can inherit DID/DDO benefits and enhance interoperability. +This document describes how Ocean assets follow the DID/DDO specification, such that Ocean assets can inherit DID/DDO benefits and enhance interoperability. DIDs and DDOs follow the [specification defined by the World Wide Web Consortium (W3C)](https://w3c-ccg.github.io/did-spec/). -Decentralized identifiers (DIDs) are a new type of identifier that enables verifiable, decentralized digital identity. Each DID is associated with a unique entity. DIDs may represent humans, objects, and more. +Decentralized identifiers (DIDs) are a type of identifier that enable verifiable, decentralized digital identity. Each DID is associated with a unique entity, and DIDs may represent humans, objects, and more. -A DID Document (DDO) is JSON blob that holds information about the DID. Given a DID, a _resolver_ will return the DDO of that DID. +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. -If a DID is the index key in a key-value pair, then the DID Document is the value to which the index key points. -The combination of a DID and its associated DID Document forms the root record for a decentralized identifier. +## Rules for DID & DDO -DIDs and DDOs follow [this specification](https://w3c-ccg.github.io/did-spec/) defined by the World Wide Web Consurtium (W3C). +An _asset_ in Ocean represents a downloadable file, compute service, or similar. Each asset is a _resource_ under the control of a _publisher_. The Ocean network itself does _not_ store the actual resource (e.g. files). -## Rules for DIDs & DDOs in Ocean +An _asset_ has a DID and DDO. The DDO should include [metadata](#metadata) about the asset, and define access in at least one [service](#services). Only _owners_ or _delegated users_ can modify the DDO. -- An _asset_ in Ocean represents a downloadable file, compute service, or similar. Each asset is a _resource_ under control of a _publisher_. The Ocean network itself does _not_ store the actual resource (e.g. files). -- An asset should have a DID and DDO. The DDO should include metadata about the asset. -- The DDO can only can be modified by _owners_ or _delegated users_. -- There _must_ be at least one client library acting as _resolver_, to get a DDO from a DID. -- The DDO is stored on-chain. It's stored in in plaintext, with two exceptions: (1) the field for resource-access url is encrypted (2) the whole DDO may be encrypted, if the publisher is willing to lose 100% of discoverability. -- A metadata cache like Aquarius can help in reading and writing DDO data from the chain. +All DDOs are stored on-chain in encrypted form to be fully GDPR-compatible. A metadata cache like _Aquarius_ can help in reading, decrypting, and searching through encrypted DDO data from the chain. Because the file URLs are encrypted on top of the full DDO encryption, returning unencrypted DDOs e.g. via an API is safe to do as the file URLs will still stay encrypted. -## DID Structure +## Publishing & Retrieving DDOs -In Ocean, a DID is a string that looks like: +The DDO is stored on-chain as part of the NFT contract and stored in encrypted form using the private key of the _Provider_. To resolve it, a metadata cache like _Aquarius_ must query the provider to decrypt the DDO. + +Here is the flow: + +![DDO flow](images/ddo-flow.png) + +
+ UML source + +```text +title DDO flow + +User(Ocean library) -> User(Ocean library): Prepare DDO +User(Ocean library) -> Provider: encrypt DDO +Provider -> User(Ocean library): encryptedDDO +User(Ocean library) -> ERC721 contract: publish encryptedDDO +Aquarius <-> ERC721 contract: monitors ERC721 contract and gets MetdadataCreated Event (contains encryptedDDO) +Aquarius -> ERC721 contract: calls getMetaData() +Aquarius -> Provider: decrypt encryptedDDO, signed request using Aquarius's private key +Provider -> ERC721 contract: checks state using getMetaData() +Provider -> Provider: depending on metadataState (expired,retired) and aquarius address, validates the request +Provider -> Aquarius: DDO +Aquarius -> Aquarius : validate DDO +Aquarius -> Aquarius : cache DDO +Aquarius -> Aquarius : enhance cached DDO in response with additional infos like events & stats +``` + +
+ +## DID + +In Ocean, a DID is a string that looks like this: ```text did:op:0ebed8226ada17fde24b6bf2b95d27f8f05fcce09139ff5cec31f6d81a7cd2ea ``` +The part after `did:op:` is the ERC721 contract address(in checksum format) and the chainId (expressed as a decimal) the asset has been published to: + +```js +const checksum = sha256(ERC721 contract address + chainId) +console.log(checksum) +// 0ebed8226ada17fde24b6bf2b95d27f8f05fcce09139ff5cec31f6d81a7cd2ea +``` + It follows [the generic DID scheme](https://w3c-ccg.github.io/did-spec/#the-generic-did-scheme). -The part after `did:op:` is the asset's on-chain Ethereum address (minus the "0x"). One can be computed from the other; therefore there is a 1:1 mapping between did and Ethereum address. +## DDO -## DDO Attributes +A DDO in Ocean has these required attributes: -![DDO Content](images/ddo-content.png) +| Attribute | Type | Description | +| ----------------- | --------------------------- | -------------------------------------------------------------------------------------------------------------- | +| **`@context`** | Array of `string` | Contexts used for validation. | +| **`id`** | `string` | Computed as `sha256(address of ERC721 contract + chainId)`. | +| **`version`** | `string` | Version information in [SemVer](https://semver.org) notation referring to this DDO spec version, like `4.0.0`. | +| **`chainId`** | `number` | Stores chainId of the network the DDO was published to. | +| **`nftAddress`** | `string` | NFT contract linked to this asset | +| **`metadata`** | [Metadata](#metadata) | Stores an object describing the asset. | +| **`services`** | [Services](#services) | Stores an array of services defining access to the asset. | +| **`credentials`** | [Credentials](#credentials) | Describes the credentials needed to access a dataset in addition to the `services` definition. | -A DDO has these standard attributes: +### Metadata -- `@context` -- `id` -- `created` -- `updated` -- `publicKey` -- `authentication` -- `proof` -- `verifiableCredential` +This object holds information describing the actual asset. -In Ocean, the DDO also has: +| Attribute | Type | Required | Description | +| --------------------------- | ----------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`created`** | `ISO date/time string` | | Contains the date of the creation of the dataset content in ISO 8601 format preferably with timezone designators, e.g. `2000-10-31T01:30:00Z`. | +| **`updated`** | `ISO date/time string` | | Contains the date of last update of the dataset content in ISO 8601 format preferably with timezone designators, e.g. `2000-10-31T01:30:00Z`. | +| **`description`** | `string` | **✓** | Details of what the resource is. For a dataset, this attribute explains what the data represents and what it can be used for. | +| **`copyrightHolder`** | `string` | | The party holding the legal copyright. Empty by default. | +| **`name`** | `string` | **✓** | Descriptive name or title of the asset. | +| **`type`** | `string` | **✓** | Asset type. Includes `"dataset"` (e.g. csv file), `"algorithm"` (e.g. Python script). Each type needs a different subset of metadata attributes. | +| **`author`** | `string` | **✓** | Name of the entity generating this data (e.g. Tfl, Disney Corp, etc.). | +| **`license`** | `string` | **✓** | Short name referencing the license of the asset (e.g. Public Domain, CC-0, CC-BY, No License Specified, etc. ). If it's not specified, the following value will be added: "No License Specified". | +| **`links`** | Array of `string` | | Mapping of URL strings for data samples, or links to find out more information. Links may be to either a URL or another asset. | +| **`contentLanguage`** | `string` | | The language of the content. Use one of the language codes from the [IETF BCP 47 standard](https://tools.ietf.org/html/bcp47) | +| **`tags`** | Array of `string` | | Array of keywords or tags used to describe this content. Empty by default. | +| **`categories`** | Array of `string` | | Array of categories associated to the asset. Note: recommended to use `tags` instead of this. | +| **`additionalInformation`** | Object | | Stores additional information, this is customizable by publisher | +| **`algorithm`** | [Algorithm Metadata](#algorithm-metadata) | **✓** (for algorithm assets only) | Information about asset of `type` `algorithm` | -- `dataToken` -- `service` -- `credentials` - optional flag, which describes the credentials needed to access a dataset (see below) - -Asset metadata must be included as one of the objects inside the `"service"` array, with type `"metadata"`. - -## DDO Service Types - -There are many possible service types for a DDO. - -- `metadata` - describing the asset -- `access` - describing how the asset can be downloaded -- `compute` - describing how the asset can be computed upon - -Each asset has a `metadata` service and at least one other service. - -Each service is distinguished by the `DDO.service.type` attribute. - -Each service has an `attributes` section holding the information related to the service. That section _must_ have a `main` sub-section, holding all the mandatory information that a service has to provide. - -A part of the `attributes.main` sub-section, other optional sub-sections like `attributes.extra` can be added. These depend on the service type. - -Each service has a `timeout` (in seconds) section describing how long the service can be used after consumption is initiated. A timeout of 0 represents no time limit. - -The `cost` attribute is obsolete, as of Ocean V3. As of V3, to consume an asset, one sends exactly 1.0 datatokens of the asset, so a `cost` is not needed. - -## DDO Service Example - -Here is an example DDO service: +Example: ```json -"service": [ - { - "index": 0, - "type": "metadata", - "serviceEndpoint": "https://service/api/v1/metadata/assets/ddo/did:op:0ebed8226ada17fde24b6bf2b95d27f8f05fcce09139ff5cec31f6d81a7cd2ea", - "attributes": { - "main": {}, - "additionalInformation": {}, - "curation": {} - } - }, - { - "index": 1, - "type": "access", - "serviceEndpoint": "http://localhost:8030/api/v1/provider/services/consume", - "attributes": { - "main": { - "cost":"10", - "timeout":0 +{ + "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" + } +} +``` + +#### Algorithm Metadata + +An asset of type `algorithm` has additional attributes under `metadata.algorithm`, describing the algorithm and the Docker environment it is supposed to be run under. + +| Attribute | Type | Required | Description | +| ------------------------ | ------------------------------------------- | -------- | ------------------------------------------------------------------------------------------ | +| **`language`** | `string` | | Language used to implement the software. | +| **`version`** | `string` | | Version of the software preferably in [SemVer](https://semver.org) notation. E.g. `1.0.0`. | +| **`consumerParameters`** | [Consumer Parameters](#consumer-parameters) | | An object the defines required consumer input before running the algorithm | +| **`container`** | `container` | **✓** | Object describing the Docker container image. See below | + +The `container` object has the following attributes defining the Docker image for running the algorithm: + +| Attribute | Type | Required | Description | +| ---------------- | -------- | -------- | ----------------------------------------------------------------- | +| **`entrypoint`** | `string` | **✓** | The command to execute, or script to run inside the Docker image. | +| **`image`** | `string` | **✓** | Name of the Docker image. | +| **`tag`** | `string` | **✓** | Tag of the Docker image. | +| **`checksum`** | `string` | **✓** | Checksum of the Docker image. | + +```json +{ + "metadata": { + "created": "2020-11-15T12:27:48Z", + "updated": "2021-05-17T21:58:02Z", + "description": "Sample description", + "name": "Sample algorithm asset", + "type": "algorithm", + "author": "OPF", + "license": "https://market.oceanprotocol.com/terms", + "algorithm": { + "language": "Node.js", + "version": "1.0.0", + "container": { + "entrypoint": "node $ALGO", + "image": "ubuntu", + "tag": "latest", + "checksum": "44e10daa6637893f4276bb8d7301eb35306ece50f61ca34dcab550" }, - "additionalInformation": {} + "consumerParameters": {} } - }, + } +} +``` + +### Services + +Services define the access for an asset, and each service is represented by its respective datatoken. + +An asset should have at least one service to be actually accessible, and can have as many services which make sense for a specific use case. + +| Attribute | Type | Required | Description | +| ---------------------- | --------------------------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | +| **`id`** | `string` | **✓** | Unique ID | +| **`type`** | `string` | **✓** | Type of service (`access`, `compute`, `wss`, etc. | +| **`name`** | `string` | | Service friendly name | +| **`description`** | `string` | | Service description | +| **`datatokenAddress`** | `string` | **✓** | Datatoken address | +| **`serviceEndpoint`** | `string` | **✓** | Provider URL (schema + host) | +| **`files`** | [Files](#files) | **✓** | Encrypted file URLs. | +| **`timeout`** | `number` | **✓** | Describing how long the service can be used after consumption is initiated. A timeout of `0` represents no time limit. Expressed in seconds. | +| **`compute`** | [Compute](#compute-options) | **✓** (for compute assets only) | If service is of `type` `compute`, holds information about the compute-related privacy settings & resources. | +| **`consumerParameters`** | [Consumer Parameters](#consumer-parameters) | | An object the defines required consumer input before consuming the asset| +| **`additionalInformation`** | Object | | Stores additional information, this is customizable by publisher | + + +#### Files + +The `files` field is returned as a `string` which holds the encrypted file URLs. + +Example: + +```json +{ + "files": "0x044736da6dae39889ff570c34540f24e5e084f4e5bd81eff3691b729c2dd1465ae8292fc721e9d4b1f10f56ce12036c9d149a4dab454b0795bd3ef8b7722c6001e0becdad5caeb2005859642284ef6a546c7ed76f8b350480691f0f6c6dfdda6c1e4d50ee90e83ce3cb3ca0a1a5a2544e10daa6637893f4276bb8d7301eb35306ece50f61ca34dcab550b48181ec81673953d4eaa4b5f19a45c0e9db4cd9729696f16dd05e0edb460623c843a263291ebe757c1eb3435bb529cc19023e0f49db66ef781ca692655992ea2ca7351ac2882bf340c9d9cb523b0cbcd483731dc03f6251597856afa9a68a1e0da698cfc8e81824a69d92b108023666ee35de4a229ad7e1cfa9be9946db2d909735" +} +``` + +During the publish process, file URLs must be encrypted with a respective _Provider_ API call before storing the DDO on-chain. For this an array of objects defining the storage access details are sent. + +Type of objects supported : + + + + + + + + + + +
TypeDescriptionExample
'url'Static URL. Contains url and HTTP method + +```json +[ { - "index": 2, - "type": "compute", - "serviceEndpoint": "http://localhost:8030/api/v1/provider/services/compute", - "attributes": { - "main": { - "cost":"10", - "timeout":3600 - }, - "additionalInformation": {} - } + "type": "url", + "url": "https://url.com/file1.csv", + "method": "GET" } ] ``` -## DDO Credentials for Fine-Grained Permissions +
-By default, a consumer can access a resource if they have 1.0 datatokens. _Credentials_ allow the publisher to optionally specify finer-grained permissions. +First class integrations supported in the future : -Consider a medical data use case, where only a credentialed EU researcher can legally access a given dataset. Ocean supports this as follows: a consumer can only access the resource if they have 1.0 datatokens _and_ one of the specified `"allow"` credentials. - -This is like going to an R-rated movie, where you can only get in if you show both your movie ticket (datatoken) _and_ some some id showing you're old enough (credential). - -Only credentials that can be proven are supported. This includes Ethereum public addresses, and (in the future) W3C Verifiable Credentials and more. - -Ocean also supports `"deny"` credentials: if a consumer has any of these credentials, they cannot access the resource. - -Here's an example object with both `"allow"` and `"deny"` entries. + + + + + + + + + + + + + + +
TypeDescriptionExample
"ipfs"IPFS files ```json -"credentials":{ - "allow":[ - { - "type":"address", - "values":[ - "0x123", - "0x456" - ] - } - ] - }, - "deny":[ - { - "type":"address", - "values":[ - "0x2222", - "0x333" - ] - } - ] -} +[ + { + "type": "ipfs", + "hash": "XXX" + } +] ``` -For future usage, we can extend that with different credentials types. Example: +
"filecoin"Filecoin storage 
"arwave"Arwave 
"storj"Storj 
"sql"Sql connection, dataset is generated by a query 
+ +A service can contain multiple files, using multiple storage types. + +Example: + +```json +[ + { + "type": "url", + "url": "https://url.com/file1.csv", + "method": "GET" + }, + { + "type": "ipfs", + "hash": "XXXX" + } +] +``` + +To get information about the files after encryption, the `/fileinfo` endpoint of _Provider_ returns based on a passed DID an array of file metadata (based on the file type): + +```json +[ + { + "type": "url", + "contentLength": 100, + "contentType": "application/json" + }, + { + "type": "ipfs", + "contentLength": 130, + "contentType": "application/text" + } +] +``` + +This only concerns metadata about a file, but never the file URLs. The only way to decrypt them is to exchange at least 1 datatoken based on the respective service pricing scheme. + +#### Compute Options + +An asset with a service of `type` `compute` has the following additional attributes under the `compute` object. This object is required if the asset is of `type` `compute`, but can be omitted for `type` of `access`. + + + + + + + + + + + + + + + + +
allowRawAlgorithm + + + + + + + + + + + + + +
TypeRequiredDescription
booleanIf true, any passed raw text will be allowed to run. Useful for an algorithm drag & drop use case, but increases risk of data escape through malicious user input. Should be false by default in all implementations.
+
allowNetworkAccess + + + + + + + + + + + + + +
TypeRequiredDescription
booleanIf true, the algorithm job will have network access.
+
publisherTrustedAlgorithmPublishers + + + + + + + + + + + + + +
TypeRequiredDescription
Array of stringIf empty, then any published algorithm is allowed. Otherwise, only published algorithms by some publishers are allowed.
+
publisherTrustedAlgorithms + + + + + + + + + + + + + +
TypeRequiredDescription
Array of publisherTrustedAlgorithmsIf empty, then any published algorithm is allowed. (see below).
+
+ +The `publisherTrustedAlgorithms ` is an array of objects with the following structure: + +| Attribute | Type | Required | Description | +| ------------------------------ | -------- | -------- | ------------------------------------------------------------------------- | +| **`did`** | `string` | **✓** | The DID of the algorithm which is trusted by the publisher. | +| **`filesChecksum`** | `string` | **✓** | Hash of algorithm's `files` section (as `string`). | +| **`containerSectionChecksum`** | `string` | **✓** | Hash of algorithm's `metadata.algorithm.container` section (as `string`). | + +To produce `filesChecksum`: + +```js +sha256(JSON.Stringify(algorithm_ddo.services[0].files)) +``` + +To produce `containerSectionChecksum`: + +```js +sha256(JSON.Stringify(algorithm_ddo.metadata.algorithm.container)) +``` + +Example: ```json { - "type": "credential3Box", - "values": ["profile1", "profile2"] + "services": [ + { + "id": "1", + "type": "access", + "files": "0x044736da6dae39889ff570c34540f24e5e084f...", + "name": "Download service", + "description": "Download service", + "datatokenAddress": "0x123", + "serviceEndpoint": "https://myprovider.com", + "timeout": 0 + }, + { + "id": "2", + "type": "compute", + "files": "0x6dd05e0edb460623c843a263291ebe757c1eb3...", + "name": "Compute service", + "description": "Compute service", + "datatokenAddress": "0x124", + "serviceEndpoint": "https://myprovider.com", + "timeout": 0, + "compute": { + "allowRawAlgorithm": false, + "allowNetworkAccess": true, + "publisherTrustedAlgorithmPublishers": ["0x234", "0x235"], + "publisherTrustedAlgorithms": [ + { + "did": "did:op:123", + "filesChecksum": "100", + "containerSectionChecksum": "200" + }, + { + "did": "did:op:124", + "filesChecksum": "110", + "containerSectionChecksum": "210" + } + ] + } + } + ] +} +``` + +#### Consumer Parameters + +Sometimes, you may need some input before downloading a dataset or running an algorithm. +Examples: + +- You want to know the desired sampling interval of data in your dataset, before the user is going to download it. Your dataset URL is `https://example.com/mydata`. So you will define a field called `sampling`, ask the user to enter a value and then this parameter is going to be added to the URL of your dataset as query parameters: `https://example.com/mydata?sampling=10` +- Before running an algorithm, you need to know how many iterations should it perform. You define a field called `iterations`, ask the user to enter a value and this parameter is stored in a specific location in your Computer-to-Data pod for the algorithm to read and use that value. + +It's an array of elements, each element object defines a field. +An element looks like: + +```json +{ + "name": "hometown", + "type": "text", + "label": "Hometown", + "required": true, + "description": "What is your hometown?", + "default": "Nowhere", + "options": [] +} +``` + +where: + +- name = defines the parameter name (this is sent as HTTP param or key towards algo) +- type = defines the form type (text, number, select, boolean) +- label = defines the label which is displayed +- required = if this field is mandatory to have a consumer input. +- default = default value +- description = description of this element +- options = for select types, a list of options + +Example: + +```json +[ + { + "name":"hometown", + "type": "text", + "label": "Hometown", + "required": true, + "default": "Nowhere" + "description":"What is your hometown?" + }, + { + "name":"age", + "type": "number", + "label": "Age", + "required": false, + "default": 0 + "description":"Please fill your age" + }, + { + "name":"developer", + "type": "boolean", + "label": "Developer", + "required": false, + "default": false + "description":"Are you a developer?" + }, + { + "name":"preference", + "type": "select", + "label": "Date", + "required": false, + "default": "nodejs" + "options": [ + { + "nodejs" : "I love NodeJs" + }, + { + "python" : "I love Python" + } + ], + "description": "Do you like NodeJs or Python" + }, +] +``` + +Algorithms will have access to a JSON file located at /data/inputs/algoCustomData.json, which contains the keys/values for input data required. Example: + +```json +{ + "surname": "John", + "age": 10, + "developer": false, + "preference": "nodejs" +} +``` + +### Credentials + +By default, a consumer can access a resource if they have 1 datatoken. _Credentials_ allow the publisher to optionally specify more fine-grained permissions. + +Consider a medical data use case, where only a credentialed EU researcher can legally access a given dataset. Ocean supports this as follows: a consumer can only access the resource if they have 1 datatoken _and_ one of the specified `"allow"` credentials. + +This is like going to an R-rated movie, where you can only get in if you show both your movie ticket (datatoken) _and_ some identification showing you're old enough (credential). + +Only credentials that can be proven are supported. This includes Ethereum public addresses, and in the future [W3C Verifiable Credentials](https://www.w3.org/TR/vc-data-model/) and more. + +Ocean also supports `"deny"` credentials: if a consumer has any of these credentials, they can not access the resource. + +Here's an example object with both `"allow"` and `"deny"` entries: + +```json +{ + "credentials": { + "allow": [ + { + "type": "address", + "values": ["0x123", "0x456"] + } + ], + "deny": [ + { + "type": "address", + "values": ["0x2222", "0x333"] + } + ] + } +} +``` + +### DDO Checksum + +In order to ensure the integrity of the DDO, a checksum is computed for each DDO: + +```js +const checksum = sha256(JSON.stringify(ddo)) +``` + +The checksum hash is used when publishing/updating metadata using the `setMetaData` function in the ERC721 contract, and is stored in the event generated by the ERC721 contract: + +```solidity +event MetadataCreated( + address indexed createdBy, + uint8 state, + string decryptorUrl, + bytes flags, + bytes data, + bytes metaDataHash, + uint256 timestamp, + uint256 blockNumber +); + +event MetadataUpdated( + address indexed updatedBy, + uint8 state, + string decryptorUrl, + bytes flags, + bytes data, + bytes metaDataHash, + uint256 timestamp, + uint256 blockNumber +); +``` + +_Aquarius_ should always verify the checksum after data is decrypted via a _Provider_ API call. + +### State + +Each asset has a state, which is held by the NFT contract. The possible states are: + +| State | Description | +| ------- | ------------------------------- | +| **`0`** | Active. | +| **`1`** | End-of-life. | +| **`2`** | Deprecated (by another asset). | +| **`3`** | Revoked by publisher. | +| **`4`** | Ordering is temporary disabled. | + +## Aquarius Enhanced DDO Response + +The following fields are added by _Aquarius_ in its DDO response for convenience reasons, where an asset returned by _Aquarius_ inherits the DDO fields stored on-chain. + +These additional fields are never stored on-chain, and are never taken into consideration when [hashing the DDO](#ddo-checksum). + +### NFT + +The `nft` object contains information about the ERC721 NFT contract which represents the intellectual property of the publisher. + +| Attribute | Type | Description | +| -------------- | ---------------------- | ------------------------------------------------------------------------- | +| **`address`** | `string` | Contract address of the deployed ERC721 NFT contract. | +| **`name`** | `string` | Name of NFT set in contract. | +| **`symbol`** | `string` | Symbol of NFT set in contract. | +| **`owner`** | `string` | ETH account address of the NFT owner. | +| **`state`** | `number` | State of the asset reflecting the NFT contract value. See [State](#state) | +| **`created`** | `ISO date/time string` | Contains the date of NFT creation. | +| **`tokenURI`** | `string` | tokenURI | + +Example: + +```json +{ + "nft": { + "address": "0x000000", + "name": "Ocean Protocol Asset v4", + "symbol": "OCEAN-A-v4", + "owner": "0x0000000", + "state": 0, + "created": "2000-10-31T01:30:00Z" + } +} +``` + +### Datatokens + +The `datatokens` array contains information about the ERC20 datatokens attached to [asset services](#services). + +| Attribute | Type | Description | +| --------------- | -------- | ------------------------------------------------ | +| **`address`** | `string` | Contract address of the deployed ERC20 contract. | +| **`name`** | `string` | Name of NFT set in contract. | +| **`symbol`** | `string` | Symbol of NFT set in contract. | +| **`serviceId`** | `string` | ID of the service the datatoken is attached to. | + +Example: + +```json +{ + "datatokens": [ + { + "address": "0x000000", + "name": "Datatoken 1", + "symbol": "DT-1", + "serviceId": "1" + }, + { + "address": "0x000001", + "name": "Datatoken 2", + "symbol": "DT-2", + "serviceId": "2" + } + ] +} +``` + +### Event + +The `event` section contains information about the last transaction that created or updated the DDO. + +Example: + +```json +{ + "event": { + "tx": "0x8d127de58509be5dfac600792ad24cc9164921571d168bff2f123c7f1cb4b11c", + "block": 12831214, + "from": "0xAcca11dbeD4F863Bb3bC2336D3CE5BAC52aa1f83", + "contract": "0x1a4b70d8c9DcA47cD6D0Fb3c52BB8634CA1C0Fdf", + "datetime": "2000-10-31T01:30:00" + } +} +``` + +### Purgatory + +Contains information about an asset's purgatory status defined in [`list-purgatory`](https://github.com/oceanprotocol/list-purgatory). Marketplace interfaces are encouraged to prevent certain user actions like adding liquidity on assets in purgatory. + +| Attribute | Type | Description | +| ------------ | --------- | --------------------------------------------------------------------------------------------- | +| **`state`** | `boolean` | If `true`, asset is in purgatory. | +| **`reason`** | `string` | If asset is in purgatory, contains the reason for being there as defined in `list-purgatory`. | + +Example: + +```json +{ + "purgatory": { + "state": true, + "reason": "Copyright violation" + } +} +``` + +```json +{ + "purgatory": { + "state": false + } +} +``` + +### Statistics + +The `stats` section contains different statistics fields. + +| Attribute | Type | Description | +| ------------ | -------- | ------------------------------------------------------------------------------------------------------------ | +| **`orders`** | `number` | How often an asset was ordered, meaning how often it was either downloaded or used as part of a compute job. | + +Example: + +```json +{ + "stats": { + "orders": 4 + } +} +``` + +## Full Enhanced DDO Example + +```json +{ + "@context": ["https://w3id.org/did/v1"], + "id": "did:op:ACce67694eD2848dd683c651Dab7Af823b7dd123", + "version": "4.0.0", + "chainId": 1, + "nftAddress": "0x123", + "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" + }, + "services": [ + { + "id": "1", + "type": "access", + "files": "0x044736da6dae39889ff570c34540f24e5e084f4e5bd81eff3691b729c2dd1465ae8292fc721e9d4b1f10f56ce12036c9d149a4dab454b0795bd3ef8b7722c6001e0becdad5caeb2005859642284ef6a546c7ed76f8b350480691f0f6c6dfdda6c1e4d50ee90e83ce3cb3ca0a1a5a2544e10daa6637893f4276bb8d7301eb35306ece50f61ca34dcab550b48181ec81673953d4eaa4b5f19a45c0e9db4cd9729696f16dd05e0edb460623c843a263291ebe757c1eb3435bb529cc19023e0f49db66ef781ca692655992ea2ca7351ac2882bf340c9d9cb523b0cbcd483731dc03f6251597856afa9a68a1e0da698cfc8e81824a69d92b108023666ee35de4a229ad7e1cfa9be9946db2d909735", + "name": "Download service", + "description": "Download service", + "datatokenAddress": "0x123", + "serviceEndpoint": "https://myprovider.com", + "timeout": 0, + "consumerParameters": [ + { + "name": "surname", + "type": "text", + "label": "Name", + "required": true, + "default": "NoName", + "description": "Please fill your name" + }, + { + "name": "age", + "type": "number", + "label": "Age", + "required": false, + "default": 0, + "description": "Please fill your age" + } + ] + }, + { + "id": "2", + "type": "compute", + "files": "0x044736da6dae39889ff570c34540f24e5e084f4e5bd81eff3691b729c2dd1465ae8292fc721e9d4b1f10f56ce12036c9d149a4dab454b0795bd3ef8b7722c6001e0becdad5caeb2005859642284ef6a546c7ed76f8b350480691f0f6c6dfdda6c1e4d50ee90e83ce3cb3ca0a1a5a2544e10daa6637893f4276bb8d7301eb35306ece50f61ca34dcab550b48181ec81673953d4eaa4b5f19a45c0e9db4cd9729696f16dd05e0edb460623c843a263291ebe757c1eb3435bb529cc19023e0f49db66ef781ca692655992ea2ca7351ac2882bf340c9d9cb523b0cbcd483731dc03f6251597856afa9a68a1e0da698cfc8e81824a69d92b108023666ee35de4a229ad7e1cfa9be9946db2d909735", + "name": "Compute service", + "description": "Compute service", + "datatokenAddress": "0x124", + "serviceEndpoint": "https://myprovider.com", + "timeout": 3600, + "compute": { + "allowRawAlgorithm": false, + "allowNetworkAccess": true, + "publisherTrustedAlgorithmPublishers": ["0x234", "0x235"], + "publisherTrustedAlgorithms": [ + { + "did": "did:op:123", + "filesChecksum": "100", + "containerSectionChecksum": "200" + }, + { + "did": "did:op:124", + "filesChecksum": "110", + "containerSectionChecksum": "210" + } + ] + } + } + ], + "credentials": { + "allow": [ + { + "type": "address", + "values": ["0x123", "0x456"] + } + ], + "deny": [ + { + "type": "address", + "values": ["0x2222", "0x333"] + } + ] + }, + + "nft": { + "address": "0x123", + "name": "Ocean Protocol Asset v4", + "symbol": "OCEAN-A-v4", + "owner": "0x0000000", + "state": 0, + "created": "2000-10-31T01:30:00", + "tokenURI": "xxx" + }, + + "datatokens": [ + { + "address": "0x000000", + "name": "Datatoken 1", + "symbol": "DT-1", + "serviceId": "1" + }, + { + "address": "0x000001", + "name": "Datatoken 2", + "symbol": "DT-2", + "serviceId": "2" + } + ], + + "event": { + "tx": "0x8d127de58509be5dfac600792ad24cc9164921571d168bff2f123c7f1cb4b11c", + "block": 12831214, + "from": "0xAcca11dbeD4F863Bb3bC2336D3CE5BAC52aa1f83", + "contract": "0x1a4b70d8c9DcA47cD6D0Fb3c52BB8634CA1C0Fdf", + "datetime": "2000-10-31T01:30:00" + }, + + "purgatory": { + "state": false + }, + + "stats": { + "orders": 4 + } } ``` diff --git a/content/concepts/images/architecture.png b/content/concepts/images/architecture.png index f479632e..97084f85 100644 Binary files a/content/concepts/images/architecture.png and b/content/concepts/images/architecture.png differ diff --git a/content/concepts/images/datanft-and-datatoken.png b/content/concepts/images/datanft-and-datatoken.png new file mode 100644 index 00000000..2a0c79fb Binary files /dev/null and b/content/concepts/images/datanft-and-datatoken.png differ diff --git a/content/concepts/images/ddo-content.png b/content/concepts/images/ddo-content.png deleted file mode 100644 index 4c7eb293..00000000 Binary files a/content/concepts/images/ddo-content.png and /dev/null differ diff --git a/content/concepts/images/ddo-flow.png b/content/concepts/images/ddo-flow.png new file mode 100644 index 00000000..fab9a027 Binary files /dev/null and b/content/concepts/images/ddo-flow.png differ diff --git a/content/concepts/images/use-case.png b/content/concepts/images/use-case.png new file mode 100644 index 00000000..a581963f Binary files /dev/null and b/content/concepts/images/use-case.png differ diff --git a/content/concepts/introduction.md b/content/concepts/introduction.md index 980b897f..3ee06bab 100644 --- a/content/concepts/introduction.md +++ b/content/concepts/introduction.md @@ -3,20 +3,23 @@ title: Introduction description: Ocean Protocol - Tools for the Web3 Data Economy --- -In Ocean Protocol, each data service gets its own ERC20 **datatoken**. This enables data wallets, data exchanges, and data co-ops by directly leveraging crypto wallets, exchanges, and more. +In Ocean Protocol, each asset gets its own ERC721 **data NFT** and one(or more) ERC20 **datatokens**. This enables data wallets, data exchanges, and data co-ops by directly leveraging crypto wallets, exchanges, and more. OCEAN token is used for staking, and more. [Here](https://oceanprotocol.com/token) are details. -Ocean Protocol provides tools for developers to _build data markets_, and to _manage datatokens_ for use in DeFi. +Ocean Protocol provides tools for developers to _build data markets_, and to _manage data NFTs and datatokens_ for use in DeFi. **Build Data Markets.** Use Ocean Protocol software tools to build your own data marketplace, by either forking [Ocean Market](https://market.oceanprotocol.com/) code or building up with Ocean components. -**Manage Datatokens for use in DeFi.** Use Ocean [JavaScript](https://github.com/oceanprotocol/ocean.js) or [Python](https://github.com/oceanprotocol/ocean.py) drivers to manage datatokens: +**Manage datatokens and data NFTs for use in DeFi.** Use Ocean [JavaScript](https://github.com/oceanprotocol/ocean.js) or [Python](https://github.com/oceanprotocol/ocean.py) drivers to manage data NFTs and datatokens: -- _Publish and consume data services:_ downloadable files or compute-to-data. Use Ocean to deploy a new [ERC20](https://github.com/ethereum/EIPs/blob/7f4f0377730f5fc266824084188cc17cf246932e/EIPS/eip-20.md) datatoken contract for each data service, then mint datatokens. +- _Publish and consume data services:_ downloadable files or compute-to-data. Use Ocean to deploy a new [ERC721](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md) and [ERC20](https://github.com/ethereum/EIPs/blob/7f4f0377730f5fc266824084188cc17cf246932e/EIPS/eip-20.md) datatoken contract for each data service, then mint datatokens. - _Transfer datatokens_ to another owner (or approve & transferFrom). -- _Manage pools._ Deploy OCEAN-datatoken [Balancer](https://www.balancer.finance/) pools, buy & sell datatokens (swap), and add & remove liquidity. +- _Manage pools._ Deploy OCEAN-datatoken [Balancer](https://www.balancer.fi/) pools, buy & sell datatokens (swap), and add & remove liquidity. - _And more._ Use ERC20 support in [web3.js](https://web3js.readthedocs.io/), [web3.py](https://web3py.readthedocs.io/en/stable/examples.html#working-with-an-erc20-token-contract) and Solidity to connect datatokens with crypto wallets and other DeFi services. + +**Compute-to-Data** +Ocean's "Compute-to-Data" feature gives compute access to privately-held data, which never leaves the data owner’s premises. Ocean-based marketplaces enable the monetization of private data while preserving privacy. [Here](/tutorials/compute-to-data-architecture/) are details. diff --git a/content/concepts/networks.md b/content/concepts/networks.md index a7e17303..d68358b4 100644 --- a/content/concepts/networks.md +++ b/content/concepts/networks.md @@ -3,182 +3,13 @@ title: Supported Networks description: All the public networks the Ocean Protocol contracts are deployed to, and additional core components deployed to them. --- -Ocean Protocol contracts are deployed on multiple public networks. You can always find the most up-to-date deployment addresses for all individual contracts in the [address.json](https://github.com/oceanprotocol/contracts/blob/master/artifacts/address.json) artifact. +Ocean Protocol contracts are deployed on multiple public networks. You can always find the most up-to-date deployment addresses for all individual contracts in the [address.json](https://github.com/oceanprotocol/contracts/blob/v4main/addresses/address.json). In each network, you’ll need ETH to pay for gas, and OCEAN for certain Ocean actions. Because the Ethereum mainnet is a network for production settings, ETH and OCEAN tokens have real value on there. The ETH and OCEAN tokens in each test network don’t have real value and are used for testing-purposes only. They can be obtained with _faucets_ to dole out ETH and OCEAN. -The universal Aquarius Endpoint is `https://aquarius.oceanprotocol.com`. - -## Ethereum Mainnet - -The Ethereum Mainnet is Ocean’s production network. - -MetaMask and other ERC20 wallets default to Ethereum mainnet, therefore your wallet is almost certainly pointing to Ethereum by default. - -**Tokens** - -- ETH: - - Native token to pay transaction fees - - [Exchanges to purchase](https://www.coingecko.com/en/coins/ethereum#markets) -- OCEAN: - - Address: [0x967da4048cD07aB37855c090aAF366e4ce1b9F48](https://etherscan.io/token/0x967da4048cD07aB37855c090aAF366e4ce1b9F48) - - [Exchanges to purchase](https://oceanprotocol.com/token#get) - -**Additional Components** - -| What | URL | -| ------------ | -------------------------------------------- | -| Explorer | https://etherscan.io | -| Ocean Market | https://market.oceanprotocol.com | -| Provider | `https://provider.mainnet.oceanprotocol.com` | -| Subgraph | `https://subgraph.mainnet.oceanprotocol.com` | - -## Polygon Mainnet - -Ocean is [deployed](https://blog.oceanprotocol.com/ocean-on-polygon-network-8abad19cbf47) to the [Polygon](https://polygon.technology/) production network. Polygon's native token is MATIC. - -If you don't find Polygon as a predefined network in your wallet, you can connect to it manually via [this guide](/tutorials/metamask-setup/#set-up-custom-network) and the parameters below. - -| What | Value | -| ------------------ | ---------------------------------------- | -| Network Name | `Matic Mainnet` | -| RPC | `https://rpc.polygon.oceanprotocol.com/` | -| Chain Id | `137` | -| Currency Symbol | `MATIC` | -| Block Explorer URL | `https://explorer.matic.network/` | - -**Tokens** - -- MATIC: - - Native token to pay transaction fees - - [Exchanges to purchase](https://www.coingecko.com/en/coins/polygon#markets) -- Polygon OCEAN: - - Address: [0x282d8efCe846A88B159800bd4130ad77443Fa1A1](https://polygonscan.com/token/0x282d8efCe846A88B159800bd4130ad77443Fa1A1) - - [Exchanges to purchase](https://oceanprotocol.com/token#get) - -**Additional Components** - -| What | URL | -| ------------ | -------------------------------------------------------------------- | -| Explorer | https://polygonscan.com/ | -| Ocean Market | Point wallet to Polygon network, at https://market.oceanprotocol.com | -| Provider | `https://provider.polygon.oceanprotocol.com` | -| Subgraph | `https://subgraph.polygon.oceanprotocol.com` | - -**Bridge** - -Check our [Polygon Bridge guide](/tutorials/polygon-bridge/) to learn how you can deposit, withdraw and send tokens. - -## Moonriver - -Ocean is deployed to [Moonriver](https://moonbeam.network/networks/moonriver/), another production network. Moonriver's native token is MOVR. - -If you don't find Moonriver as a predefined network in your wallet, you can connect to it manually via [Ocean's guide](/tutorials/metamask-setup/#set-up-custom-network) and the parameters below. - -| What | Value | -| ------------------ | ----------------------------------- | -| Network Name | `Moonriver` | -| RPC | `https://rpc.moonriver.moonbeam.network`| -| Chain Id | `1285` | -| Currency Symbol | `MOVR` | -| Block Explorer URL | `https://blockscout.moonriver.moonbeam.network` | - -**Tokens** - -- Moonriver MOVR: - - Native token to pay transaction fees - - Exchanges to purchase: [List](https://coinmarketcap.com/currencies/moonriver/markets/) -- Moonriver OCEAN: - - Address: [0x99C409E5f62E4bd2AC142f17caFb6810B8F0BAAE](https://blockscout.moonriver.moonbeam.network/address/0x99C409E5f62E4bd2AC142f17caFb6810B8F0BAAE/) - - [Exchanges to purchase](https://oceanprotocol.com/token#get) - -**Additional Components** - -| What | URL | -| ------------ | ---------------------------------------------------------------- | -| Explorer | https://blockscout.moonriver.moonbeam.network/ | -| Ocean Market | Point wallet to Moonriver network, at https://market.oceanprotocol.com | -| Provider | `https://provider.moonriver.oceanprotocol.com` | -| Subgraph | `https://subgraph.moonriver.oceanprotocol.com` | - -**Bridge** - -Use [Anyswap](https://anyswap.exchange/#/bridge) to bridge between ETH Mainnet and Moonriver +The universal Aquarius Endpoint is `https://v4.aquarius.oceanprotocol.com`. -## Energy Web Chain - -Ocean is deployed to [Energy Web Chain](https://energy-web-foundation.gitbook.io/energy-web/technology/the-stack/trust-layer-energy-web-chain), another production network. Energy Web's native token is EWT. - -If you don't find Energy Web Chain as a predefined network in your wallet, you can connect to it manually via [Ocean's guide](/tutorials/metamask-setup/#set-up-custom-network) and the parameters below. - -| What | Value | -| ------------------ | ----------------------------------- | -| Network Name | `Energy Web Chain` | -| RPC | `https://rpc.energyweb.org` | -| Chain Id | `246` | -| Currency Symbol | `EWT` | -| Block Explorer URL | `https://explorer.energyweb.org/` | - -**Tokens** - -- Energy Web Chain EWT: - - Native token to pay transaction fees - - Exchanges to purchase: [List](https://coinmarketcap.com/currencies/energy-web-token/markets/) -- Energy Web Chain OCEAN: - - Address: [0x593122aae80a6fc3183b2ac0c4ab3336debee528](https://explorer.energyweb.org/tokens/0x593122AAE80A6Fc3183b2AC0c4ab3336dEbeE528) - - [Exchanges to purchase](https://oceanprotocol.com/token#get) - -**Additional Components** - -| What | URL | -| ------------ | ---------------------------------------------------------------- | -| Explorer | https://explorer.energyweb.org/ | -| Ocean Market | Point wallet to Energy Web Chain network, at https://market.oceanprotocol.com | -| Provider | `https://provider.energyweb.oceanprotocol.com` | -| Subgraph | `https://subgraph.energyweb.oceanprotocol.com` | - -**Bridge** - -Use [Carbonswap bridge](https://bridge.carbonswap.exchange/bridge) to bridge between ETH Mainnet and Energy Web Chain - - - -## Binance Smart Chain - -Ocean is deployed to [Binance Smart Chain (BSC)](https://academy.binance.com/en/articles/how-to-get-started-with-binance-smart-chain-bsc), another production network. BSC's native token is BNB - the Binance token. - -If you don't find BSC as a predefined network in your wallet, you can connect to it manually via [Binance's guide](https://academy.binance.com/en/articles/connecting-metamask-to-binance-smart-chain) or [Ocean's guide](/tutorials/metamask-setup/#set-up-custom-network) and the parameters below. - -| What | Value | -| ------------------ | ----------------------------------- | -| Network Name | `Smart Chain` | -| RPC | `https://bsc-dataseed.binance.org/` | -| Chain Id | `56` | -| Currency Symbol | `BNB` | -| Block Explorer URL | `https://bscscan.com` | - -**Tokens** - -- BSC BNB: - - Native token to pay transaction fees - - Exchanges to purchase: typically [binance.com](https://www.binance.com) -- BSC OCEAN: - - Address: [0xdce07662ca8ebc241316a15b611c89711414dd1a](https://bscscan.com/token/0xdce07662ca8ebc241316a15b611c89711414dd1a) - - [Exchanges to purchase](https://oceanprotocol.com/token#get) - -**Additional Components** - -| What | URL | -| ------------ | ---------------------------------------------------------------- | -| Explorer | https://bscscan.com/ | -| Ocean Market | Point wallet to BSC network, at https://market.oceanprotocol.com | -| Provider | `https://provider.bsc.oceanprotocol.com` | -| Subgraph | `https://subgraph.bsc.oceanprotocol.com` | - -**Bridge** - -Check our [BSC Bridge guide](/tutorials/bsc-bridge/) to learn how you can deposit, withdraw and send tokens. ## Ropsten @@ -201,8 +32,8 @@ In MetaMask and other ERC20 wallets, click on the network name dropdown, then se | ------------ | -------------------------------------------------------------------- | | Explorer | https://ropsten.etherscan.io | | Ocean Market | Point wallet to Ropsten network, at https://market.oceanprotocol.com | -| Provider | `https://provider.ropsten.oceanprotocol.com` | -| Subgraph | `https://subgraph.ropsten.oceanprotocol.com` | +| Provider | `https://v4.provider.ropsten.oceanprotocol.com` | +| Subgraph | `https://v4.subgraph.ropsten.oceanprotocol.com` | ## Rinkeby @@ -225,8 +56,8 @@ In MetaMask and other ERC20 wallets, click on the network name dropdown, then se | ------------ | -------------------------------------------------------------------- | | Explorer | https://rinkeby.etherscan.io | | Ocean Market | Point wallet to Rinkeby network, at https://market.oceanprotocol.com | -| Provider | `https://provider.rinkeby.oceanprotocol.com` | -| Subgraph | `https://subgraph.rinkeby.oceanprotocol.com` | +| Provider | `https://v4.provider.rinkeby.oceanprotocol.com` | +| Subgraph | `https://v4.subgraph.rinkeby.oceanprotocol.com` | ## Mumbai @@ -249,31 +80,34 @@ If you don't find Mumbai as a predefined network in your wallet, you can connect | ------------ | ------------------------------------------------------------------- | | Explorer | https://mumbai.polygonscan.com | | Ocean Market | Point wallet to Mumbai network, at https://market.oceanprotocol.com | -| Provider | `https://provider.mumbai.oceanprotocol.com` | -| Subgraph | `https://subgraph.mumbai.oceanprotocol.com` | +| Provider | `https://v4.provider.mumbai.oceanprotocol.com` | +| Subgraph | `https://v4.subgraph.mumbai.oceanprotocol.com` | -## Celo Alfajores -Alfajores is a Celo test network for developers building on the Celo platform. +## Moonbase -Celo docs: https://docs.celo.org/. +Moonbase is a test network tuned for Moonbeam / Moonriver. -Wallet setup: https://celo.org/developers/wallet +If you don't find Moonbase as a predefined network in your wallet, you can connect to it manually via [Moonbase guide](https://docs.moonbeam.network/learn/platform/networks/moonbase/). **Tokens** -- Alfajores CELO: +- Moonbase DEV: - Native token to pay transaction fees - - [Faucet](https://celo.org/developers/faucet). -- Alfajores OCEAN: - - Address: [0xd8992Ed72C445c35Cb4A2be468568Ed1079357c8](https://alfajores-blockscout.celo-testnet.org/address/0xd8992Ed72C445c35Cb4A2be468568Ed1079357c8/) - + - Facuet: See above guide You may find others by [searching](https://www.google.com/search?q=moonbase+dev+faucet). +- Moonbase OCEAN: + - Address: [0xF6410bf5d773C7a41ebFf972f38e7463FA242477](https://moonbase.moonscan.io/token/0xF6410bf5d773C7a41ebFf972f38e7463FA242477) + - [Faucet](https://faucet.moonbase.oceanprotocol.com/) **Additional Components** | What | URL | | ------------ | ------------------------------------------------------------------- | -| Explorer | https://alfajores-blockscout.celo-testnet.org/ | +| Explorer | https://moonbase.moonscan.io/ | +| Ocean Market | Point wallet to Moonbase network, at https://market.oceanprotocol.com | +| Provider | `https://v4.provider.moonbase.oceanprotocol.com/` | +| Subgraph | `https://v4.subgraph.moonbase.oceanprotocol.com` | + ## Local / Ganache diff --git a/content/concepts/roles.md b/content/concepts/roles.md new file mode 100644 index 00000000..9470be03 --- /dev/null +++ b/content/concepts/roles.md @@ -0,0 +1,37 @@ +--- +title: Data NFTs and datatoken roles +description: The permissions stored on chain in the contracts control the access to the data NFT (ERC721) and datatoken (ERC20) smart contract functions. +--- + +The permissions are stored in the data NFT (ERC721) smart contract. The data NFT (ERC721) and datatoken (ERC20) smart contracts both use this information to restrict access to the smart contract functions. The tables below list restricted actions that are accessible only to the allowed users. + +## Roles in data NFT (ERC721) smart contract + +| Action ↓ / Role → | NFT Owner | Manager | ERC20 Deployer | Store Updater | Metadata Updater | +| --------------------------------- | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | +| Set token URI | | | | | | +| Add manager |
🗸
| | | | | +| Remove manager |
🗸
| | | | | +| Clean permissions |
🗸
| | | | | +| Set base URI |
🗸
| | | | | +| Set Metadata state | | | | |
🗸
| +| Set Metadata | | | | |
🗸
| +| Create new datatoken | | |
🗸
| | | +| Executes any other smart contract | |
🗸
| | | | +| Set new key-value in store | | | |
🗸
| | + +## Roles in datatoken (ERC20) smart contract + +| Action ↓ / Role → | ERC20 Deployer | Minter | NFT owner | Fee manager | +| --------------------------- | ------------------ | ------------------ | ------------------ | ------------------ | +| Deploy pool |
🗸
| | | | +| Create Fixed Rate exchange |
🗸
| | | | +| Create Dispenser |
🗸
| | | | +| Add minter |
🗸
| | | | +| Remove minter |
🗸
| | | | +| Add fee manager |
🗸
| | | | +| Remove fee manager |
🗸
| | | | +| Set data |
🗸
| | | | +| Clean permissions | | |
🗸
| | +| Mint | |
🗸
| | | +| Set fee collector | | | |
🗸
| diff --git a/content/tutorials/azure-for-provider.md b/content/tutorials/azure-for-provider.md index 1dd3169e..fef6efaf 100644 --- a/content/tutorials/azure-for-provider.md +++ b/content/tutorials/azure-for-provider.md @@ -2,7 +2,8 @@ title: Set Up Azure Storage description: Tutorial about how to set up Azure storage for use with Ocean. --- -*Note: This needs updating for Ocean V3.* + +_Note: This needs updating for Ocean V3._ This tutorial is for publishers who want to get started using Azure to store some of their data assets. (Some data assets could also be stored in other places.) @@ -174,4 +175,3 @@ You now have a storage account, but you don't have any data stored under it yet. Azure Storage can store blobs, files, queues and tables. To work with Ocean Network, you should store your files in [Azure Blob storage (also called object storage)](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction), not Azure Files. Besides Azure Storage Explorer, there are [many other Azure Storage APIs, libraries and tools](https://docs.microsoft.com/en-us/azure/storage/common/storage-introduction#storage-apis-libraries-and-tools). - diff --git a/content/tutorials/compute-to-data-algorithms.md b/content/tutorials/compute-to-data-algorithms.md index 34197cf8..4d35907a 100644 --- a/content/tutorials/compute-to-data-algorithms.md +++ b/content/tutorials/compute-to-data-algorithms.md @@ -42,7 +42,7 @@ To do so, create a Dockerfile with the appropriate instructions for dependency m We also collect some [example images](https://github.com/oceanprotocol/algo_dockers) which you can also view in Dockerhub. -When publishing an algorithm through the [Ocean Market](https://market.oceanprotoco.com), these properties can be set via the publish UI. +When publishing an algorithm through the [Ocean Market](https://market.oceanprotocol.com), these properties can be set via the publish UI. ### Environment Examples diff --git a/content/tutorials/marketplace-fees.md b/content/tutorials/marketplace-fees.md new file mode 100644 index 00000000..af439724 --- /dev/null +++ b/content/tutorials/marketplace-fees.md @@ -0,0 +1,94 @@ +--- +title: Fees +description: The Ocean Protocol defines various fees for creating a sustainability loop. +--- + +## Path to sustainability + +Ocean Protocol achieves sustainability via the [Web3 sustainability loop](https://blog.oceanprotocol.com/the-web3-sustainability-loop-b2a4097a36e). + +- The project grows and improves through the efforts of OceanDAO grant recipients. +- The OceanDAO votes to decide which proposals receive grants. +- Grant funds are sourced from the Ocean Protocol community treasury. +- The Ocean Protocol community collects fees when users interact with the protocol, thus completing the sustainability loop. + +## Fee types + +### Swap fee + +Swap fees are collected whenever someone swaps a datatoken for base token (e.g., OCEAN) or base token for a datatoken. The swap could be inside a pool (using an automated market maker) or in a fixed-rate exchange. +These are the fees that are applied whenever a user swaps base token or datatoken: + +- Publisher Marketplace swap fee +- Consumer Marketplace swap fee +- Provider Consumption Fees +- [Ocean Community Fee](#ocean-community-fee) + +### Publish fee + +Publish fees can be charged to a publisher when they publish an asset. + +Currently, the Ocean marketplace does not charge a publishing fee. Custom marketplaces can charge a publishing fee by adding an extra transaction in the publish flow. + +Based on the use case of the marketplace, the marketplace owner can decide if this fee should be charged or not. + +### Consume fee + +Consume fees (aka. Order fees) are charged when a user holding a datatoken exchanges it for the right to download an asset or to start a compute job that uses the asset. + +These are the fees that are applied whenever a user consumes an asset: + +- Consume Market Consumption Fee +- Publisher Market Consumption Fee +- Provider Consumption Fees +- [Ocean Community Fee](#ocean-community-fee) + +### Ocean Community fee + +Ocean's smart contracts collect **Ocean Community fees** during swap and order operations. These fees are reinvested in community projects via OceanDAO and other initiatives. + +For swaps involving approved base tokens like OCEAN and H2O, the Ocean Community swap fee is 0.1%. For swaps involving other base tokens, the Ocean Community swap fee is 0.2%. The Ocean Community order fee is 0.3 DT per order operation. + +These fees can be updated by the Ocean Protocol Foundation. + +### Provider fee + +Provider is a component of Ocean Protocol's ecosystem that facilitates data consumption, starts compute jobs, encrypts DDOs, and decrypts DDOs. Provider also validates if the user can access a particular data asset or service. To learn more about Provider, click [here](https://github.com/oceanprotocol/provider). + +Provider fees are paid to the individual or organization running their Provider instance when the user orders an asset. These fees can be set to an absolute amount, not as a percentage. The provider can also specify which token the fees must be paid in - they don't have to be the same token used in the consuming market. + +Provider fees can also be used to charge for computing resources. Based on the compute resources needed to run an algorithm in the Compute-to-Data environment, a consumer can choose the amount to pay according to their needs. + +These fees incentivize individuals and organizations to run their provider instances and charge consumers according to resource usage. + +## Fee values + +The table is periodically updated. Users are advised to confirm new values through the [contracts](https://github.com/oceanprotocol/contracts) and the [market](https://github.com/oceanprotocol/market). + +| Swap Fees | Value in Ocean Market, using any Provider | Value in Other Markets | +| :------------------------------------------------------------ | :----------------------------------------:| :----------------------------------------------------------------------------------------------------------------------------------------------- | +| publishMarket: Pools | 0% | Set in the market config, by the publishing market.
Min = 0.001%
Max = 10% | +| publishMarket: FixedRate | 0% | Set in the market config, by the publishing market.
Min = 0.001%
Max = 50% | +| consumeMarket: Pools | 0% | Set in market config, by the consuming market.
Min = 0.001%
Max = 10% | +| consumeMarket: FixedRate
ERC20Template | 0% | 0% | +| consumeMarket: FixedRate
EnterpriseTemplate | 0% | Set in market config, by the consuming market. | +| Ocean Community: Pools & FixedRate
OCEAN, H2O as base token| 0.1% | 0.1% | +| Ocean Community: Pools & FixedRate
other base token | 0.2% | 0.2% | +| Pool Liquidity Provider (LP) | 1% | Set by the pool creator on contract deployment.
Contracts
Min = 0.001%
Max = 10%
Market
Min = 0.1%
Max = 10%| +| Publish Fees | 0% | 0% | +| Order Fees
1 datatoken available to get dataset acces | | | +| publishMarket
Absolute value, in any token. E.g. 5 USDT | 0 | Set in market config, by the publishing market. | +| consumeMarket
Absolute value, in any token. E.g. 2 DAI | 0 | Set in market config, by the consuming market. | +| Ocean Community
Fixed price in DT | 0.03 DT | 0.03 DT | + +| Ocean Provider Fees | OPF Provider | 3rd party Provider | +| :------------------------------------------------------------ | :----------------------------------------:| :----------------------------------------------------------------------------------------------------------------------------------------------- | +| Token in which fee is charged: `PROVIDER_FEE_TOKEN` | OCEAN | E.g. USDC | +| Download: `COST_PER_MB` | 0 | Set in Provider envvars. | +| Compute: `COST_PER_MIN`
Environment: 1 CPU, 60 secs max | 0 | Set in OperatorEngine envvars. | +| Compute: `COST_PER_MIN`
Environment: 1 CPU, 1 hour max | 1.0 OCEAN/min | Set in OperatorEngine envvars. | +| Ocean Community | 0% of the Provider fee | 0% of the Provider fee | + +## Further reading + +- [The Web3 Sustainability Loop](https://blog.oceanprotocol.com/the-web3-sustainability-loop-b2a4097a36e) diff --git a/content/tutorials/marketplace-publish-data-asset.md b/content/tutorials/marketplace-publish-data-asset.md index ee6edf8f..568dd8a6 100644 --- a/content/tutorials/marketplace-publish-data-asset.md +++ b/content/tutorials/marketplace-publish-data-asset.md @@ -27,8 +27,8 @@ Ocean Market provides a convenient interface for individuals as well as organiza 5. After clicking submit, approve the transactions in the wallet. Here, you can see Metamask window. - Deploy a new Datatoken contract. - ![publish submit part-1](images/marketplace/submit-1.png 'Create Datatoken contract') + Deploy a new datatoken contract. + ![publish submit part-1](images/marketplace/submit-1.png 'Create datatoken contract') Contract interaction. ![publish submit part-2](images/marketplace/submit-2.png 'Contract interaction') diff --git a/content/tutorials/marketplace-swap-and-stake.md b/content/tutorials/marketplace-swap-and-stake.md index 87fa9c21..6adb247e 100644 --- a/content/tutorials/marketplace-swap-and-stake.md +++ b/content/tutorials/marketplace-swap-and-stake.md @@ -3,7 +3,7 @@ title: Swap and/or Stake Tokens description: --- -## Swap Ocean Tokens against Datatokens +## Swap OCEAN Tokens against datatokens 1. Search for the desired asset published on the [Ocean Marketplace](https://market.oceanprotocol.com/). diff --git a/content/tutorials/marketplace.md b/content/tutorials/marketplace.md index e40ea5a0..89359c1e 100644 --- a/content/tutorials/marketplace.md +++ b/content/tutorials/marketplace.md @@ -3,43 +3,19 @@ title: Set Up a Marketplace description: --- -In Ocean, marketplaces and publishers are different roles. A common setup is for one organization to do both. We focus on that here. +## About marketplace -## The Steps +Ocean Protocol's [marketplace](https://market.oceanprotocol.com/) provides a web interface for accessing assets published on the chain. By default, assets metadata is pulled from Aquarius, component hosted by Ocean Protocol. To extend the existing features of the marketplace, developers can fork the marketplace. -1. Develop the first cut of the app. -1. Prepare some initial data assets. -1. Deploy to production. +By doing so, developers can: -## Develop a First Cut of the App +- Change the name of the marketplace. +- Implement their own branding and style. +- Change the source of the asset information. +- Customise the fees -Here are some approaches: +## Forking marketplace -- Fork [Ocean Market](https://github.com/oceanprotocol/market) code. -- Build from [Ocean React hooks](https://github.com/oceanprotocol/react). -- Build up from [ocean.js](https://github.com/oceanprotocol/ocean.js) or [ocean.py](https://github.com/oceanprotocol/ocean.py) drivers. +To setup a marketplace follow the steps here: -## Prepare Some Initial Data Assets - -When you deploy, you'll want some initial data assets for your market to offer. - -Ocean supports several types, such as Azure and S3 storage. The [tutorials](/tutorials/) section provides more info. - -## Deploy to Production - -When developing your app, you'll likely use Barge to run all the Ocean Protocol components on your local machine. - -When it comes time to go to production, you will have to run these components: - -- Your marketplace/publisher app -- Aquarius (with Elasticsearch) -- Provider-py - -Of course, there are many other things that must be handled in production: - -- Security of the infrastructure where the software is running -- Monitoring -- Log aggregation, storage, and search -- Handling crashes or other faults - -Each of those is beyond the scope of these docs. +[Launch a blockchain-based data marketplace in under 1 hour](https://blog.oceanprotocol.com/launch-a-blockchain-based-data-marketplace-in-under-1-hour-9baa85a65ece) diff --git a/content/tutorials/on-premise-for-provider.md b/content/tutorials/on-premise-for-provider.md index a3d26825..e78dbc40 100644 --- a/content/tutorials/on-premise-for-provider.md +++ b/content/tutorials/on-premise-for-provider.md @@ -2,7 +2,8 @@ title: Set Up On-Premise Storage description: Tutorial about how to set up on-premise storage for use with Ocean. --- -*Note: This needs updating for Ocean V3.* + +_Note: This needs updating for Ocean V3._ To enable Provider to use files stored in on-premise storage (i.e. files with an URL not containing `core.windows.net` or `s3://`), there is _nothing to do, other than make sure Provider can resolve the URLs_. In particular, you don't have to set any Provider-specific configuration settings, e.g. in the `[osmosis]` section of the Provider config file or in some special Provider environment variables. diff --git a/data/sidebars/concepts.yml b/data/sidebars/concepts.yml index 18037d4e..04ea2055 100644 --- a/data/sidebars/concepts.yml +++ b/data/sidebars/concepts.yml @@ -6,27 +6,27 @@ link: /concepts/quickstart/ - title: Architecture Overview link: /concepts/architecture/ + - title: Data NFT and Datatoken + link: /concepts/datanft-and-datatoken/ + - title: Roles + link: /concepts/roles/ - title: Supported Networks link: /concepts/networks/ - - title: Deployments - link: /concepts/deployments/ - - title: Projects using Ocean - link: /concepts/projects-using-ocean/ - group: Compute-to-Data items: - - title: Introduction + - title: Overview link: /concepts/compute-to-data/ - group: Specifying Assets items: - - title: DIDs & DDOs + - title: DID & DDO link: /concepts/did-ddo/ - - title: DDO Metadata - link: /concepts/ddo-metadata/ - group: Contribute items: + - title: Projects using Ocean + link: /concepts/projects-using-ocean/ - title: Ways to Contribute link: /concepts/contributing/ - title: Get Funding diff --git a/data/sidebars/tutorials.yml b/data/sidebars/tutorials.yml index 75280355..8325e1e8 100644 --- a/data/sidebars/tutorials.yml +++ b/data/sidebars/tutorials.yml @@ -34,6 +34,8 @@ items: - title: Set Up a Marketplace link: /tutorials/marketplace/ + - title: Fees + link: /tutorials/marketplace-fees/ - group: Compute-to-Data items: diff --git a/docs/apis.md b/docs/apis.md index 2881bf1e..0b276e77 100644 --- a/docs/apis.md +++ b/docs/apis.md @@ -1,8 +1,8 @@ # API References -- [Overview](#Overview) -- [Swagger specs](#Swagger-specs) -- [TypeDoc specs](#TypeDoc-specs) +- [Overview](#overview) +- [Swagger specs](#swagger-specs) +- [TypeDoc specs](#typedoc-specs) ## Overview diff --git a/docs/github.md b/docs/github.md index ec1ddc8b..7eba3851 100644 --- a/docs/github.md +++ b/docs/github.md @@ -1,8 +1,8 @@ # GitHub Data Fetching -- [Overview](#Overview) -- [GitHub GraphQL API](#GitHub-GraphQL-API) -- [GitHub REST API](#GitHub-REST-API) +- [Overview](#overview) +- [GitHub GraphQL API](#github-graphql-api) +- [GitHub REST API](#github-rest-api) ## Overview @@ -22,8 +22,7 @@ For local development, you can simply [create a personal access token](https://g ```bash cp .env.sample .env -vi .env -# GITHUB_TOKEN=add_your_token_here +vi .env # GITHUB_TOKEN=add_your_token_here ``` An alternative to typing the above code is to just create a .env file and add this line `GITHUB_TOKEN=add_your_token_here` in it. Do not put your token in quotes. diff --git a/gatsby-config.js b/gatsby-config.js index 31879ac8..119a51f3 100755 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -155,19 +155,19 @@ module.exports = { options: { name: 'repo-read-the-docs', remote: `https://github.com/oceanprotocol/readthedocs.git`, - local: 'markdowns/', - branch: 'main', + local: 'read-the-docs', + branch: 'v4', patterns: [ - 'markdowns/ocean-py', - 'markdowns/aquarius', - 'markdowns/provider' + 'read-the-docs/ocean-py', + 'read-the-docs/aquarius', + 'read-the-docs/provider' ] } }, { resolve: 'gatsby-source-filesystem', options: { - path: `${__dirname}/markdowns/markdowns`, + path: `${__dirname}/read-the-docs/markdowns`, name: 'markdowns' } }, diff --git a/gatsby-node.js b/gatsby-node.js index 198794b1..f219ea77 100755 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -59,7 +59,9 @@ exports.createPages = ({ graphql, actions }) => { } allRepoMarkdown: allMarkdownRemark( - filter: { fileAbsolutePath: { regex: "/markdowns/markdowns/" } } + filter: { + fileAbsolutePath: { regex: "/read-the-docs/markdowns/" } + } ) { edges { node { @@ -103,6 +105,62 @@ exports.createPages = ({ graphql, actions }) => { } } } + + aquariusRestApi: allMarkdownRemark( + filter: { + frontmatter: { + title: { eq: "API.md" } + app: { eq: "aquarius" } + } + } + ) { + edges { + node { + id + html + htmlAst + tableOfContents + frontmatter { + title + description + slug + section + app + module + source + version + } + } + } + } + + providerRestApi: allMarkdownRemark( + filter: { + frontmatter: { + title: { eq: "API.md" } + app: { eq: "provider" } + } + } + ) { + edges { + node { + id + html + htmlAst + tableOfContents + frontmatter { + title + description + slug + section + app + module + source + version + } + } + } + } } ` ).then(async (result) => { @@ -135,10 +193,7 @@ exports.createPages = ({ graphql, actions }) => { // API: ocean.js const lastRelease = result.data.oceanJs.repository.releases.edges.filter( - ({ node }) => - !node.isPrerelease && - !node.isDraft && - node.releaseAssets.edges.length > 0 + ({ node }) => !node.isDraft && node.releaseAssets.edges.length > 0 )[0].node.releaseAssets.edges[0].node await createTypeDocPage( @@ -165,6 +220,21 @@ exports.createPages = ({ graphql, actions }) => { const providerList = filterMarkdownList(markdowns, 'provider') const subgraphList = filterMarkdownList(markdowns, 'ocean-subgraph') + const aquariusRestApi = result.data.aquariusRestApi.edges[0].node + await createRestApiPage( + createPage, + aquariusRestApi, + `/references/aquarius` + ) + + const providerRestApi = result.data.providerRestApi.edges[0].node + + await createRestApiPage( + createPage, + providerRestApi, + `/references/provider` + ) + await createReadTheDocsPage(createPage, 'ocean-py', oceanPyList) await createReadTheDocsPage(createPage, 'provider', providerList) await createReadTheDocsPage(createPage, 'ocean-subgraph', subgraphList) @@ -292,3 +362,22 @@ const createReadTheDocsPage = async (createPage, name, list) => { const filterMarkdownList = (markdownList, string) => { return markdownList.filter(({ node }) => node.frontmatter.app === string) } + +const createRestApiPage = async (createPage, node, slug) => { + const template = path.resolve('./src/templates/RestApi.jsx') + createPage({ + path: slug, + component: template, + context: { + node, + slug + } + }) +} + +// const getRestApiPageFromMarkdownList = (markdownList, string) => { +// return markdownList.filter( +// ({ node }) => +// node.frontmatter.app === string && node.frontmatter.slug === 'API.md' +// ) +// } diff --git a/package-lock.json b/package-lock.json index 3b9084bc..878e2253 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3177,18 +3177,6 @@ "strip-json-comments": "^3.1.1" }, "dependencies": { - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, "globals": { "version": "13.11.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", @@ -3573,10 +3561,7 @@ "cross-fetch": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz", - "integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==", - "requires": { - "node-fetch": "2.6.1" - } + "integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==" }, "form-data": { "version": "4.0.0", @@ -5158,9 +5143,9 @@ } }, "ajv": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", - "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -5195,34 +5180,44 @@ "integrity": "sha512-4g5Np4CVD3c5c/36Mj0jllEA5bQcuXF0dqakZcuHGeubBzw93EAhwRuQCzgFm4/ZwvyBMzFdtn9BcihOjnxIdQ==" }, "ansi-align": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", - "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", "requires": { - "string-width": "^3.0.0" + "string-width": "^4.1.0" }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" } }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" } } } @@ -5798,11 +5793,18 @@ "integrity": "sha512-1uIESzroqpaTzt9uX48HO+6gfnKu3RwvWdCcWSrX4csMInJfCo1yvKPNXCwXFRpJqRW25tiASb6No0YH57PXqg==" }, "axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", "requires": { - "follow-redirects": "^1.14.7" + "follow-redirects": "^1.14.8" + }, + "dependencies": { + "follow-redirects": { + "version": "1.14.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", + "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" + } } }, "axobject-query": { @@ -6581,8 +6583,7 @@ "dependencies": { "ansi-regex": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "resolved": "" }, "ansi-styles": { "version": "4.3.0", @@ -6996,9 +6997,9 @@ "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" }, "normalize-url": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", - "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==" + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==" } } }, @@ -7804,8 +7805,7 @@ "dependencies": { "ansi-regex": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "resolved": "" }, "ansi-styles": { "version": "4.3.0", @@ -8040,6 +8040,13 @@ "integrity": "sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ==", "requires": { "node-fetch": "2.6.1" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + } } }, "cross-spawn": { @@ -9570,9 +9577,9 @@ } }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "astral-regex": { @@ -9870,9 +9877,9 @@ }, "dependencies": { "ajv": { - "version": "8.6.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.2.tgz", - "integrity": "sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -9989,9 +9996,9 @@ } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -11394,9 +11401,9 @@ } }, "follow-redirects": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", - "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==" + "version": "1.14.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", + "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" }, "for-in": { "version": "1.0.2", @@ -11791,8 +11798,7 @@ "dependencies": { "ansi-regex": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "resolved": "" }, "strip-ansi": { "version": "6.0.0", @@ -12182,6 +12188,14 @@ "signal-exit": "^3.0.2", "strip-final-newline": "^2.0.0" } + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } } } }, @@ -12467,8 +12481,7 @@ "dependencies": { "ansi-regex": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "resolved": "" }, "strip-ansi": { "version": "6.0.0", @@ -12538,8 +12551,7 @@ "dependencies": { "ansi-regex": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "resolved": "" }, "ansi-styles": { "version": "4.3.0", @@ -13355,9 +13367,9 @@ } }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "debug": { "version": "4.3.1", @@ -14661,9 +14673,9 @@ } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "requires": { "is-glob": "^4.0.1" } @@ -15973,9 +15985,9 @@ } }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "ansi-styles": { "version": "4.2.1", @@ -16834,9 +16846,9 @@ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" }, "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", "dev": true }, "json-schema-traverse": { @@ -16887,14 +16899,14 @@ "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" }, "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", - "json-schema": "0.2.3", + "json-schema": "0.4.0", "verror": "1.10.0" } }, @@ -17152,12 +17164,6 @@ "resolved": "https://registry.npmjs.org/lodash.deburr/-/lodash.deburr-4.1.0.tgz", "integrity": "sha1-3bG7s+8HRYwBd7oH3hRCLLAz/5s=" }, - "lodash.differencewith": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.differencewith/-/lodash.differencewith-4.5.0.tgz", - "integrity": "sha1-uvr7yRi1UVTheRdqALsK76rIVLc=", - "dev": true - }, "lodash.every": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.every/-/lodash.every-4.6.0.tgz", @@ -17398,9 +17404,9 @@ "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==" }, "markdown-it": { - "version": "12.2.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.2.0.tgz", - "integrity": "sha512-Wjws+uCrVQRqOoJvze4HCqkKl1AsSh95iFAeQDwnyfxM09divCBSXlDR1uTvyUP3Grzpn4Ru8GeCxYPM8vkCQg==", + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", "dev": true, "requires": { "argparse": "^2.0.1", @@ -17433,33 +17439,29 @@ } }, "markdownlint": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.24.0.tgz", - "integrity": "sha512-OJIGsGFV/rC9irI5E1FMy6v9hdACSwaa+EN3224Y5KG8zj2EYzdHOw0pOJovIYmjNfEZ9BtxUY4P7uYHTSNnbQ==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.25.1.tgz", + "integrity": "sha512-AG7UkLzNa1fxiOv5B+owPsPhtM4D6DoODhsJgiaNg1xowXovrYgOnLqAgOOFQpWOlHFVQUzjMY5ypNNTeov92g==", "dev": true, "requires": { - "markdown-it": "12.2.0" + "markdown-it": "12.3.2" } }, "markdownlint-cli": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.30.0.tgz", - "integrity": "sha512-NiG8iERjwsRZtJAIyLMDdYL2O3bJVn3fUxzDl+6Iv61/YYz9H9Nzgke/v0/cW9HfGvgZHhbfI19LFMp6gbKdyw==", + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.31.1.tgz", + "integrity": "sha512-keIOMwQn+Ch7MoBwA+TdkyVMuxAeZFEGmIIlvwgV0Z1TGS5MxPnRr29XCLhkNzCHU+uNKGjU+VEjLX+Z9kli6g==", "dev": true, "requires": { - "commander": "~8.3.0", - "deep-extend": "~0.6.0", - "get-stdin": "~8.0.0", + "commander": "~9.0.0", + "get-stdin": "~9.0.0", "glob": "~7.2.0", - "ignore": "~5.1.9", + "ignore": "~5.2.0", "js-yaml": "^4.1.0", "jsonc-parser": "~3.0.0", - "lodash.differencewith": "~4.5.0", - "lodash.flatten": "~4.4.0", - "markdownlint": "~0.24.0", - "markdownlint-rule-helpers": "~0.15.0", - "minimatch": "~3.0.4", - "minimist": "~1.2.5", + "markdownlint": "~0.25.1", + "markdownlint-rule-helpers": "~0.16.0", + "minimatch": "~3.0.5", "run-con": "~1.2.10" }, "dependencies": { @@ -17470,15 +17472,15 @@ "dev": true }, "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.0.0.tgz", + "integrity": "sha512-JJfP2saEKbQqvW+FI93OYUB4ByV5cizMpFMiiJI8xDbBvQvSkIk0VvQdn1CZ8mqAO8Loq2h0gYTYtDFUZUeERw==", "dev": true }, "get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", "dev": true }, "glob": { @@ -17496,9 +17498,9 @@ } }, "ignore": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz", - "integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true }, "js-yaml": { @@ -17509,13 +17511,22 @@ "requires": { "argparse": "^2.0.1" } + }, + "minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } } } }, "markdownlint-rule-helpers": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/markdownlint-rule-helpers/-/markdownlint-rule-helpers-0.15.0.tgz", - "integrity": "sha512-A+9mswc3m/kkqpJCqntmte/1VKhDJ+tjZsERLz5L4h/Qr7ht2/BkGkgY5E7/wsxIhcpl+ctIfz+oS3PQrMOB2w==", + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/markdownlint-rule-helpers/-/markdownlint-rule-helpers-0.16.0.tgz", + "integrity": "sha512-oEacRUVeTJ5D5hW1UYd2qExYI0oELdYK72k1TKGvIeYJIbqQWAz476NAc7LNixSySUhcNl++d02DvX0ccDk9/w==", "dev": true }, "md5-file": { @@ -18364,9 +18375,9 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "minipass": { "version": "3.1.3", @@ -18508,13 +18519,12 @@ } }, "mozjpeg": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/mozjpeg/-/mozjpeg-7.0.0.tgz", - "integrity": "sha512-mH7atSbIusVTO3A4H43sEdmveN3aWn54k6V0edefzCEvOsTrbjg5murY2TsNznaztWnIgaRbWxeLVp4IgKdedQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/mozjpeg/-/mozjpeg-7.1.1.tgz", + "integrity": "sha512-iIDxWvzhWvLC9mcRJ1uSkiKaj4drF58oCqK2bITm5c2Jt6cJ8qQjSSru2PCaysG+hLIinryj8mgz5ZJzOYTv1A==", "requires": { "bin-build": "^3.0.0", - "bin-wrapper": "^4.0.0", - "logalot": "^2.1.0" + "bin-wrapper": "^4.0.0" } }, "ms": { @@ -18682,9 +18692,12 @@ "integrity": "sha1-n7CwmbzSoCGUDmA8ZCVNwAPZp6g=" }, "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } }, "node-forge": { "version": "0.10.0", @@ -19826,6 +19839,11 @@ "resolved": "https://registry.npmjs.org/physical-cpu-count/-/physical-cpu-count-2.0.0.tgz", "integrity": "sha1-GN4vl+S/epVRrXURlCtUlverpmA=" }, + "picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + }, "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", @@ -19872,9 +19890,9 @@ } }, "plist": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.4.tgz", - "integrity": "sha512-ksrr8y9+nXOxQB2osVNqrgvX/XQPOXaU4BQMKjYq8PvaY1U18mo+fKgBSwzK+luSyinOuPae956lSVcBwxlAMg==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.5.tgz", + "integrity": "sha512-83vX4eYdQp3vP9SxuYgEM/G/pJQqLUz/V/xzPrzruLs7fz7jxGQ1msZ/mg1nwZxUSuOp4sb+/bEIbRrbzZRxDA==", "requires": { "base64-js": "^1.5.1", "xmlbuilder": "^9.0.7" @@ -19950,27 +19968,18 @@ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" }, "postcss": { - "version": "7.0.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", - "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" }, "dependencies": { "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } } } }, @@ -20650,9 +20659,9 @@ "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==" }, "simple-get": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", - "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", "requires": { "decompress-response": "^4.2.0", "once": "^1.3.1", @@ -20673,9 +20682,9 @@ "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" }, "prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==" + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.1.tgz", + "integrity": "sha512-8UVbTBYGwN37Bs9LERmxCPjdvPxlEowx2urIL6urHzdb3SDq4B/Z6xLFCblrSnE4iKWcS6ziJ3aOYrc1kz/E2A==" }, "prettier-linter-helpers": { "version": "1.0.0", @@ -20719,9 +20728,9 @@ }, "dependencies": { "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "ansi-styles": { "version": "4.3.0", @@ -22047,21 +22056,85 @@ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" }, "renderkid": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.5.tgz", - "integrity": "sha512-ccqoLg+HLOHq1vdfYNm4TBeaCDIi1FLt3wGojTDSvdewUv65oTmI3cnT2E4hRjl1gzKZIPK+KZrXzlUYKnR+vQ==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.7.tgz", + "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", "requires": { - "css-select": "^2.0.2", - "dom-converter": "^0.2", - "htmlparser2": "^3.10.1", - "lodash": "^4.17.20", - "strip-ansi": "^3.0.0" + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^3.0.1" }, "dependencies": { - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "css-what": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.0.1.tgz", + "integrity": "sha512-z93ZGFLNc6yaoXAmVhqoSIb+BduplteCt1fepvwhBUQK6MNE4g6fgjpuZKJKp0esUe+vXWlIkwZZjNWoOKw0ZA==" + }, + "dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "requires": { + "boolbase": "^1.0.0" + } } } }, @@ -22532,17 +22605,6 @@ "semver": "^7.3.2" }, "dependencies": { - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, "schema-utils": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", @@ -22585,19 +22647,6 @@ "@types/json-schema": "^7.0.5", "ajv": "^6.12.4", "ajv-keywords": "^3.5.2" - }, - "dependencies": { - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - } } }, "scss-tokenizer": { @@ -22940,9 +22989,9 @@ "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" }, "simple-get": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.0.tgz", - "integrity": "sha512-ZalZGexYr3TA0SwySsr5HlgOOinS4Jsa8YB2GJ6lUNAazyAu4KG/VmzMTwAt2YVXzzVj8QmefmAonZIK2BSGcQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", "requires": { "decompress-response": "^6.0.0", "once": "^1.3.1", @@ -24994,8 +25043,7 @@ "dependencies": { "ansi-regex": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "resolved": "" }, "ansi-styles": { "version": "4.3.0", @@ -25183,9 +25231,9 @@ } }, "url-parse": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "requires": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -26451,11 +26499,11 @@ "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=" }, "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "requires": { - "string-width": "^1.0.2 || 2" + "string-width": "^1.0.2 || 2 || 3 || 4" } }, "widest-line": { @@ -26468,8 +26516,7 @@ "dependencies": { "ansi-regex": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "resolved": "" }, "emoji-regex": { "version": "8.0.0", diff --git a/package.json b/package.json index 45ac2709..18e2eaa3 100644 --- a/package.json +++ b/package.json @@ -10,14 +10,14 @@ "ssr": "npm run build && serve -s public/", "format": "prettier --ignore-path .gitignore './**/*.{css,scss,yml,js,jsx,ts,tsx,json}' --write", "lint:js": "eslint --ignore-path .gitignore --ignore-path .prettierignore --ext .js,.jsx .", - "lint:md": "markdownlint './**/*.{md,markdown}' --ignore './{node_modules,external,public,.cache,markdowns}/**/*'", + "lint:md": "markdownlint './**/*.{md,markdown}' --ignore './{node_modules,external,public,.cache,markdowns,read-the-docs}/**/*'", "lint:yml": "prettier '**/*.{yml,yaml}' --list-different", "lint": "run-p --continue-on-error lint:js lint:md lint:yml", "test": "npm run lint" }, "dependencies": { "@oceanprotocol/art": "^3.2.0", - "axios": "^0.25.0", + "axios": "^0.26.1", "classnames": "^2.3.1", "gatsby": "^2.32.13", "gatsby-image": "^3.11.0", @@ -73,10 +73,10 @@ "eslint-plugin-prettier": "^4.0.0", "git-format-staged": "^2.1.3", "husky": "^7.0.4", - "markdownlint-cli": "^0.30.0", + "markdownlint-cli": "^0.31.1", "node-sass": "^5.0.0", "npm-run-all": "^4.1.5", - "prettier": "^2.5.1" + "prettier": "^2.6.1" }, "repository": { "type": "git", diff --git a/src/components/Header.jsx b/src/components/Header.jsx index 16d0bf66..0bf03a13 100755 --- a/src/components/Header.jsx +++ b/src/components/Header.jsx @@ -3,6 +3,7 @@ import { Link, StaticQuery, graphql } from 'gatsby' import { ReactComponent as Logo } from '@oceanprotocol/art/logo/logo.svg' import styles from './Header.module.scss' import SearchButton from './Search/SearchButton' +import ToggleSwitch from './ToggleSwitch' const query = graphql` query { @@ -51,6 +52,9 @@ const Header = () => (
+
+ +
diff --git a/src/components/HeaderHome.jsx b/src/components/HeaderHome.jsx index 8f186867..99e24634 100644 --- a/src/components/HeaderHome.jsx +++ b/src/components/HeaderHome.jsx @@ -4,6 +4,7 @@ import { ReactComponent as Logo } from '@oceanprotocol/art/logo/logo.svg' import Content from '../components/Content' import styles from './HeaderHome.module.scss' import SearchButton from '../components/Search/SearchButton' +import ToggleSwitch from './ToggleSwitch' const HeaderHome = () => ( (

{siteTitle}

{siteDescription} -

+
+
+
+ +
+

diff --git a/src/components/HeaderHome.module.scss b/src/components/HeaderHome.module.scss index 44168b33..5a4ab8d6 100644 --- a/src/components/HeaderHome.module.scss +++ b/src/components/HeaderHome.module.scss @@ -47,6 +47,7 @@ } } -.searchButtonContainer { - margin-top: $spacer * 0.5 ; +.container { + margin-top: $spacer * 0.5; + align-items: 'center'; } diff --git a/src/components/ToggleSwitch.jsx b/src/components/ToggleSwitch.jsx new file mode 100644 index 00000000..6ebda7d2 --- /dev/null +++ b/src/components/ToggleSwitch.jsx @@ -0,0 +1,23 @@ +import React from 'react' +import styles from './ToggleSwitch.module.scss' + +const ToggleSwitch = () => { + return ( +
+ { + if (window) { + window.open('https://v3.docs.oceanprotocol.com/', '_self') + } + }} + /> + +
+ ) +} + +export default ToggleSwitch diff --git a/src/components/ToggleSwitch.module.scss b/src/components/ToggleSwitch.module.scss new file mode 100644 index 00000000..bb762e9f --- /dev/null +++ b/src/components/ToggleSwitch.module.scss @@ -0,0 +1,69 @@ +@import 'variables'; + +.switchButton { + background: rgba(255, 255, 255, 0.56); + border-radius: 0.5rem; + overflow: hidden; + width: $spacer * 4; + text-align: center; + font-size: $font-size-base; + letter-spacing: 1px; + color: $brand-purple; + position: relative; + padding-right: $spacer * 2; + + &:before { + content: 'v3'; + position: absolute; + top: 0; + bottom: 0; + right: 0; + width: $spacer * 2; + display: flex; + align-items: center; + justify-content: center; + z-index: 3; + pointer-events: none; + } + + &Checkbox { + cursor: pointer; + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: 100%; + height: 100%; + opacity: 0; + + &:checked + .switchButtonLabel:before { + transform: translateX($spacer * 2); + transition: transform 300ms linear; + } + + & + .switchButtonLabel { + position: relative; + padding: 0 0; + display: block; + user-select: none; + pointer-events: none; + + &:before { + content: ''; + background: $brand-grey-lighter; + height: 100%; + width: 100%; + position: absolute; + left: 0; + top: 0; + border-radius: 0.5rem; + transform: translateX(0); + transition: transform 300ms; + } + + .switchButtonLabelSpan { + position: relative; + } + } + } +} diff --git a/src/styles/_variables.scss b/src/styles/_variables.scss index 385a08d5..640590f8 100644 --- a/src/styles/_variables.scss +++ b/src/styles/_variables.scss @@ -68,4 +68,4 @@ $narrowWidth: 35rem; $box-shadow-color: rgba(0, 0, 0, 0.2); $border-color: #e2e2e2; -$background-content: #fff; \ No newline at end of file +$background-content: #fff; diff --git a/src/styles/box.module.scss b/src/styles/box.module.scss index 5a53046a..22ba49fb 100644 --- a/src/styles/box.module.scss +++ b/src/styles/box.module.scss @@ -1,23 +1,23 @@ @import 'variables'; .box { - display: block; - background: $background-content; - border-radius: $border-radius; - border: 1px solid $border-color; - box-shadow: 0 6px 17px 0 $box-shadow-color; - padding: $spacer * 0.5; - } - - @media (min-width: 40rem) { - .box { - padding: var($spacer); - } - } - - a.box:hover, - a.box:focus { - outline: 0; - transform: translate3d(0, -0.1rem, 0); - box-shadow: 0 10px 25px 0 $box-shadow-color; + display: block; + background: $background-content; + border-radius: $border-radius; + border: 1px solid $border-color; + box-shadow: 0 6px 17px 0 $box-shadow-color; + padding: $spacer * 0.5; +} + +@media (min-width: 40rem) { + .box { + padding: var($spacer); } +} + +a.box:hover, +a.box:focus { + outline: 0; + transform: translate3d(0, -0.1rem, 0); + box-shadow: 0 10px 25px 0 $box-shadow-color; +} diff --git a/src/templates/Doc.jsx b/src/templates/Doc.jsx index 8332d655..fc10c403 100644 --- a/src/templates/Doc.jsx +++ b/src/templates/Doc.jsx @@ -118,7 +118,7 @@ export const pageQuery = graphql` query DocBySlug($slug: String!) { markdownRemark(fields: { slug: { eq: $slug } }) { id - tableOfContents(maxDepth: 2) + tableOfContents(maxDepth: 3) html htmlAst frontmatter { diff --git a/src/templates/RestApi.jsx b/src/templates/RestApi.jsx new file mode 100644 index 00000000..5b458a41 --- /dev/null +++ b/src/templates/RestApi.jsx @@ -0,0 +1,49 @@ +import React from 'react' +import { Helmet } from 'react-helmet' +import Layout from '../components/Layout' +import Content from '../components/Content' +import HeaderSection from '../components/HeaderSection' +import Sidebar from '../components/Sidebar' +import stylesDoc from '../templates/Doc.module.scss' +import Seo from '../components/Seo' +import DocContent from '../components/DocContent' +import PropTypes from 'prop-types' + +export default function RestApiDoc({ location, pageContext }) { + const { node, slug } = pageContext + return ( + <> + + + + + + + + + +
+ +
+ +
+
+
+
+ + ) +} + +RestApiDoc.propTypes = { + location: PropTypes.object.isRequired, + pageContext: PropTypes.object.isRequired +}