diff --git a/.env.example b/.env.example index 6fc16b3..a289af8 100644 --- a/.env.example +++ b/.env.example @@ -1 +1 @@ -PRIVATE_KEY= +PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" diff --git a/Makefile b/Makefile index 9a900bc..d1651be 100644 --- a/Makefile +++ b/Makefile @@ -4,9 +4,18 @@ install: poetry install pre-commit install -run-demo: +demo: python3 examples/demo.py +async-demo: + python3 examples/async_demo.py + +paranets-demo: + python3 examples/paranets_demo.py + +async-paranets-demo: + python3 examples/async_paranets_demo.py + ruff: ruff check --fix ruff format @@ -15,4 +24,8 @@ help: @echo "Available commands:" @echo " install - Install dependencies and set up pre-commit hooks" @echo " ruff - Format code and fix linting issues using ruff" - @echo " run-demo - Run /examples/demo.py file" + @echo " demo - Run /examples/demo.py file" + @echo " async-demo - Run /examples/async_demo.py file" + @echo " paranet-demo - Run /examples/paranet_demo.py file" + @echo " async-paranet-demo - Run /examples/async_paranet_demo.py file" + diff --git a/README.md b/README.md index 3f15b5f..b3483d5 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,8 @@ 🚀 Getting Started
  • 📄 License
  • @@ -172,21 +173,49 @@ In order to use in the local environment, make sure to [run the local DKG networ
    -### Installation +### Library Installation -Create virtual environment (you can choose any existing folder this command will create configurations and virtual env for python): +Run the command to install dkg.py library using pip: + +```bash +pip install dkg +``` + +pip x: + +```bash +pipx install dkg +``` + +or poetry: + +```bash +poetry add dkg +``` + +
    + +More information about the library can be found in the [documentation](https://docs.origintrail.io/dkg-v8-current-version/v8-dkg-sdk/dkg-v8-py-client). + +--- + +
    + +### Installation for developers + +Create a virtual environment (you can choose any existing folder). This command will create configurations and virtual env for python: ```bash python3 -m venv /path/to/folder ``` -Inside of previously generated folder you will find activate script in bin folder and run it: +Inside of previously generated folder you will find the 'activate' script in bin folder. Run it: ```bash source /path/to/folder/bin/activate ``` -Install dependencies and configure pre-commit hooks: +Install dependencies and configure pre-commit hooks for linting and formatting: ```bash make install @@ -198,6 +227,12 @@ Now you can run a demo example file (you need to have the local DKG network runn make run-demo ``` +or an async demo example file: + +```bash +make run-async-demo +``` +

    (back to top)

    diff --git a/dkg/assertion.py b/dkg/assertion.py deleted file mode 100644 index 8c38f01..0000000 --- a/dkg/assertion.py +++ /dev/null @@ -1,65 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at - -# http://www.apache.org/licenses/LICENSE-2.0 - -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -from typing import Literal - -from dkg.managers.manager import DefaultRequestManager -from dkg.modules.module import Module -from dkg.types import JSONLD, HexStr -from dkg.utils.merkle import MerkleTree, hash_assertion_with_indexes -from dkg.utils.metadata import generate_assertion_metadata -from dkg.utils.rdf import format_content - - -class Assertion(Module): - def __init__(self, manager: DefaultRequestManager): - self.manager = manager - - def format_graph(self, content: dict[Literal["public", "private"], JSONLD]): - return format_content(content) - - def get_public_assertion_id( - self, content: dict[Literal["public", "private"], JSONLD] - ) -> HexStr: - assertions = format_content(content) - - return MerkleTree( - hash_assertion_with_indexes(assertions["public"]), - sort_pairs=True, - ).root - - def get_size(self, content: dict[Literal["public", "private"], JSONLD]) -> int: - assertions = format_content(content) - public_assertion_metadata = generate_assertion_metadata(assertions["public"]) - - return public_assertion_metadata["size"] - - def get_triples_number( - self, content: dict[Literal["public", "private"], JSONLD] - ) -> int: - assertions = format_content(content) - public_assertion_metadata = generate_assertion_metadata(assertions["public"]) - - return public_assertion_metadata["triples_number"] - - def get_chunks_number( - self, content: dict[Literal["public", "private"], JSONLD] - ) -> int: - assertions = format_content(content) - public_assertion_metadata = generate_assertion_metadata(assertions["public"]) - - return public_assertion_metadata["chunks_number"] diff --git a/dkg/clients/async_dkg.py b/dkg/clients/async_dkg.py index 3ff7b00..63c8221 100644 --- a/dkg/clients/async_dkg.py +++ b/dkg/clients/async_dkg.py @@ -29,6 +29,7 @@ from dkg.providers.blockchain.async_blockchain import AsyncBlockchainProvider from dkg.providers.node.async_node_http import AsyncNodeHTTPProvider from dkg.services.node_services.async_node_service import AsyncNodeService +from dkg.modules.paranet.async_paranet import AsyncParanet from dkg.services.blockchain_services.async_blockchain_service import ( AsyncBlockchainService, ) @@ -38,6 +39,7 @@ class AsyncDKG(AsyncModule): asset: AsyncKnowledgeAsset node: AsyncNode graph: AsyncGraph + paranet: AsyncParanet def __init__( self, @@ -58,6 +60,9 @@ def __init__( ), "node": AsyncNode(self.manager, self.node_service), "graph": AsyncGraph(self.manager, self.input_service, self.node_service), + "paranet": AsyncParanet( + self.manager, self.input_service, self.blockchain_service + ), } self._attach_modules(modules) diff --git a/dkg/clients/dkg.py b/dkg/clients/dkg.py index 9ba1e1c..0f009cf 100644 --- a/dkg/clients/dkg.py +++ b/dkg/clients/dkg.py @@ -17,12 +17,10 @@ from functools import wraps -from dkg.assertion import Assertion from dkg.modules.asset.asset import KnowledgeAsset from dkg.modules.graph.graph import Graph from dkg.managers.manager import DefaultRequestManager from dkg.modules.module import Module -from dkg.modules.network.network import Network from dkg.modules.node.node import Node from dkg.modules.paranet.paranet import Paranet from dkg.providers import BlockchainProvider, NodeHTTPProvider @@ -34,10 +32,8 @@ class DKG(Module): - assertion: Assertion asset: KnowledgeAsset paranet: Paranet - network: Network node: Node graph: Graph @@ -52,15 +48,15 @@ def __init__( self.initialize_services(config) modules = { - "assertion": Assertion(self.manager), "asset": KnowledgeAsset( self.manager, self.input_service, self.node_service, self.blockchain_service, ), - "paranet": Paranet(self.manager), - "network": Network(self.manager), + "paranet": Paranet( + self.manager, self.input_service, self.blockchain_service + ), "node": Node(self.manager), "graph": Graph(self.manager, self.input_service, self.node_service), } diff --git a/dkg/constants.py b/dkg/constants.py index 67e9474..61a25f7 100644 --- a/dkg/constants.py +++ b/dkg/constants.py @@ -1,4 +1,4 @@ -from enum import Enum, auto +from enum import Enum, auto, StrEnum from dkg.types import AutoStrEnumUpperCase # Licensed to the Apache Software Foundation (ASF) under one @@ -55,33 +55,32 @@ class DefaultParameters(Enum): GAS_LIMIT_MULTIPLIER: int = 1 PARANET_UAL: None = None GET_SUBJECT_UAL: bool = False - REPOSITORY: str = "dkg" -class OutputTypes(Enum): - NQUADS: str = "N-QUADS" - JSONLD: str = "JSON-LD" +class OutputTypes(StrEnum): + NQUADS = "N-QUADS" + JSONLD = "JSON-LD" -class Environments(Enum): - DEVELOPMENT: str = "development" - DEVNET: str = "devnet" - TESTNET: str = "testnet" - MAINNET: str = "mainnet" +class Environments(StrEnum): + DEVELOPMENT = "development" + DEVNET = "devnet" + TESTNET = "testnet" + MAINNET = "mainnet" -class BlockchainIds(Enum): - HARDHAT_1: str = "hardhat1:31337" - HARDHAT_2: str = "hardhat2:31337" - BASE_DEVNET: str = "base:84532" - GNOSIS_DEVNET: str = "gnosis:10200" - NEUROWEB_DEVNET: str = "otp:2160" - BASE_TESTNET: str = "base:84532" - GNOSIS_TESTNET: str = "gnosis:10200" - NEUROWEB_TESTNET: str = "otp:20430" - BASE_MAINNET: str = "base:8453" - GNOSIS_MAINNET: str = "gnosis:100" - NEUROWEB_MAINNET: str = "otp:2043" +class BlockchainIds(StrEnum): + HARDHAT_1 = "hardhat1:31337" + HARDHAT_2 = "hardhat2:31337" + BASE_DEVNET = "base:84532" + GNOSIS_DEVNET = "gnosis:10200" + NEUROWEB_DEVNET = "otp:2160" + BASE_TESTNET = "base:84532" + GNOSIS_TESTNET = "gnosis:10200" + NEUROWEB_TESTNET = "otp:20430" + BASE_MAINNET = "base:8453" + GNOSIS_MAINNET = "gnosis:100" + NEUROWEB_MAINNET = "otp:2043" class OperationStatuses(str, Enum): @@ -157,9 +156,6 @@ class OperationStatuses(str, Enum): }, } -PRIVATE_HISTORICAL_REPOSITORY = "privateHistory" -PRIVATE_CURRENT_REPOSITORY = "privateCurrent" - class Operations(Enum): PUBLISH = "publish" diff --git a/dkg/data/interfaces/KnowledgeCollection.json b/dkg/data/interfaces/KnowledgeCollection.json index 3eaeebf..79ff058 100644 --- a/dkg/data/interfaces/KnowledgeCollection.json +++ b/dkg/data/interfaces/KnowledgeCollection.json @@ -451,6 +451,45 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "paranetKnowledgeCollectionsRegistry", + "outputs": [ + { + "internalType": "contract ParanetKnowledgeCollectionsRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paranetKnowledgeMinersRegistry", + "outputs": [ + { + "internalType": "contract ParanetKnowledgeMinersRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paranetsRegistry", + "outputs": [ + { + "internalType": "contract ParanetsRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "paymasterManager", diff --git a/dkg/data/interfaces/Paranet.json b/dkg/data/interfaces/Paranet.json index 04ce899..08bc7d7 100644 --- a/dkg/data/interfaces/Paranet.json +++ b/dkg/data/interfaces/Paranet.json @@ -42,6 +42,27 @@ "name": "InvalidParanetNodesAccessPolicy", "type": "error" }, + { + "inputs": [ + { + "internalType": "address", + "name": "paranetKnowledgeCollectionStorageAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "paranetKnowledgeCollectionTokenId", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "paranetId", + "type": "bytes32" + } + ], + "name": "KnowledgeCollectionIsAPartOfOtherParanet", + "type": "error" + }, { "inputs": [ { @@ -184,12 +205,17 @@ "inputs": [ { "internalType": "address", - "name": "knowledgeAssetStorageAddress", + "name": "knowledgeCollectionStorageAddress", "type": "address" }, { "internalType": "uint256", - "name": "tokenId", + "name": "knowledgeCollectionTokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "knowledgeAssetTokenId", "type": "uint256" } ], @@ -200,12 +226,17 @@ "inputs": [ { "internalType": "address", - "name": "knowledgeAssetStorageAddress", + "name": "knowledgeCollectionStorageAddress", "type": "address" }, { "internalType": "uint256", - "name": "tokenId", + "name": "knowledgeCollectionTokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "knowledgeAssetTokenId", "type": "uint256" } ], @@ -216,12 +247,17 @@ "inputs": [ { "internalType": "address", - "name": "knowledgeAssetStorageAddress", + "name": "knowledgeCollectionStorageAddress", "type": "address" }, { "internalType": "uint256", - "name": "tokenId", + "name": "knowledgeCollectionTokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "knowledgeAssetTokenId", "type": "uint256" } ], @@ -248,12 +284,17 @@ "inputs": [ { "internalType": "address", - "name": "knowledgeAssetStorageAddress", + "name": "knowledgeCollectionStorageAddress", "type": "address" }, { "internalType": "uint256", - "name": "tokenId", + "name": "knowledgeCollectionTokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "knowledgeAssetTokenId", "type": "uint256" } ], @@ -293,29 +334,35 @@ { "indexed": true, "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, { "indexed": true, "internalType": "uint256", - "name": "paranetKATokenId", + "name": "paranetKCTokenId", "type": "uint256" }, { "indexed": true, + "internalType": "uint256", + "name": "paranetKATokenId", + "type": "uint256" + }, + { + "indexed": false, "internalType": "address", - "name": "knowledgeAssetStorageContract", + "name": "knowledgeCollectionStorageContract", "type": "address" }, { "indexed": false, "internalType": "uint256", - "name": "knowledgeAssetTokenId", + "name": "knowledgeCollectionId", "type": "uint256" } ], - "name": "KnowledgeAssetSubmittedToParanet", + "name": "KnowledgeCollectionSubmittedToParanet", "type": "event" }, { @@ -324,9 +371,15 @@ { "indexed": true, "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "indexed": true, + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "indexed": true, "internalType": "uint256", @@ -349,9 +402,15 @@ { "indexed": true, "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "indexed": true, + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "indexed": true, "internalType": "uint256", @@ -374,9 +433,15 @@ { "indexed": true, "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "indexed": true, + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "indexed": true, "internalType": "uint256", @@ -399,9 +464,15 @@ { "indexed": true, "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "indexed": true, + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "indexed": true, "internalType": "uint256", @@ -424,9 +495,15 @@ { "indexed": true, "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "indexed": true, + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "indexed": true, "internalType": "uint256", @@ -449,9 +526,15 @@ { "indexed": true, "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "indexed": true, + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "indexed": true, "internalType": "uint256", @@ -474,9 +557,15 @@ { "indexed": true, "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "indexed": true, + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "indexed": true, "internalType": "uint256", @@ -499,9 +588,15 @@ { "indexed": true, "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "indexed": true, + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "indexed": true, "internalType": "uint256", @@ -524,9 +619,15 @@ { "indexed": true, "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "indexed": true, + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "indexed": true, "internalType": "uint256", @@ -549,9 +650,15 @@ { "indexed": true, "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "indexed": true, + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "indexed": true, "internalType": "uint256", @@ -574,9 +681,15 @@ { "indexed": true, "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "indexed": true, + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "indexed": true, "internalType": "uint256", @@ -611,9 +724,15 @@ { "indexed": true, "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "indexed": true, + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "indexed": true, "internalType": "uint256", @@ -642,13 +761,19 @@ { "indexed": true, "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, { "indexed": true, "internalType": "uint256", - "name": "paranetKATokenId", + "name": "paranetKCTokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "parnetKATokenId", "type": "uint256" }, { @@ -677,8 +802,8 @@ }, { "indexed": false, - "internalType": "enum ParanetLib.KnowledgeAssetsAccessPolicy", - "name": "knowledgeAssetsAccessPolicy", + "internalType": "enum ParanetLib.KnowledgeCollectionsAccessPolicy", + "name": "knowledgeCollectionsAccessPolicy", "type": "uint8" } ], @@ -691,21 +816,33 @@ { "indexed": true, "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, { "indexed": true, "internalType": "uint256", - "name": "paranetKATokenId", + "name": "paranetKCTokenId", "type": "uint256" }, { "indexed": true, + "internalType": "uint256", + "name": "paranetKATokenId", + "type": "uint256" + }, + { + "indexed": false, "internalType": "address", - "name": "paranetServiceKAStorageContract", + "name": "paranetServiceKCStorageContract", "type": "address" }, + { + "indexed": false, + "internalType": "uint256", + "name": "paranetServiceKCTokenId", + "type": "uint256" + }, { "indexed": false, "internalType": "uint256", @@ -722,9 +859,15 @@ { "indexed": true, "internalType": "address", - "name": "paranetServiceKAStorageContract", + "name": "paranetServiceKCStorageContract", "type": "address" }, + { + "indexed": true, + "internalType": "uint256", + "name": "paranetServiceKCTokenId", + "type": "uint256" + }, { "indexed": true, "internalType": "uint256", @@ -759,9 +902,15 @@ { "indexed": true, "internalType": "address", - "name": "paranetServiceKAStorageContract", + "name": "paranetServiceKCStorageContract", "type": "address" }, + { + "indexed": true, + "internalType": "uint256", + "name": "paranetServiceKCTokenId", + "type": "uint256" + }, { "indexed": true, "internalType": "uint256", @@ -794,9 +943,14 @@ "inputs": [ { "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "internalType": "uint256", "name": "paranetKATokenId", @@ -817,9 +971,14 @@ "inputs": [ { "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "internalType": "uint256", "name": "paranetKATokenId", @@ -840,9 +999,14 @@ "inputs": [ { "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "internalType": "uint256", "name": "paranetKATokenId", @@ -852,12 +1016,17 @@ "components": [ { "internalType": "address", - "name": "knowledgeAssetStorageContract", + "name": "knowledgeCollectionStorageContract", "type": "address" }, { "internalType": "uint256", - "name": "tokenId", + "name": "knowledgeCollectionTokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "knowledgeAssetTokenId", "type": "uint256" } ], @@ -875,9 +1044,14 @@ "inputs": [ { "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "internalType": "uint256", "name": "paranetKATokenId", @@ -898,9 +1072,14 @@ "inputs": [ { "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "internalType": "uint256", "name": "paranetKATokenId", @@ -917,6 +1096,47 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "paranetId", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "offset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + } + ], + "name": "getKnowledgeCollectionLocatorsWithPagination", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "knowledgeCollectionStorageContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "knowledgeCollectionTokenId", + "type": "uint256" + } + ], + "internalType": "struct ParanetLib.UniversalCollectionLocator[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "hub", @@ -965,10 +1185,10 @@ }, { "inputs": [], - "name": "paranetKnowledgeAssetsRegistry", + "name": "paranetKnowledgeCollectionsRegistry", "outputs": [ { - "internalType": "contract ParanetKnowledgeAssetsRegistry", + "internalType": "contract ParanetKnowledgeCollectionsRegistry", "name": "", "type": "address" } @@ -1032,9 +1252,14 @@ "inputs": [ { "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "internalType": "uint256", "name": "paranetKATokenId", @@ -1076,9 +1301,14 @@ "inputs": [ { "internalType": "address", - "name": "paranetServiceKAStorageContract", + "name": "paranetServiceKCStorageContract", "type": "address" }, + { + "internalType": "uint256", + "name": "paranetServiceKCTokenId", + "type": "uint256" + }, { "internalType": "uint256", "name": "paranetServiceKATokenId", @@ -1115,9 +1345,14 @@ "inputs": [ { "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "internalType": "uint256", "name": "paranetKATokenId", @@ -1138,9 +1373,14 @@ "inputs": [ { "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "internalType": "uint256", "name": "paranetKATokenId", @@ -1161,9 +1401,14 @@ "inputs": [ { "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "internalType": "uint256", "name": "paranetKATokenId", @@ -1184,9 +1429,14 @@ "inputs": [ { "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "internalType": "uint256", "name": "paranetKATokenId", @@ -1207,9 +1457,14 @@ "inputs": [ { "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "internalType": "uint256", "name": "paranetKATokenId", @@ -1225,9 +1480,14 @@ "inputs": [ { "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "internalType": "uint256", "name": "paranetKATokenId", @@ -1269,9 +1529,47 @@ "inputs": [ { "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "internalType": "uint256", + "name": "paranetKnowledgeCollectionTokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "paranetKnowledgeAssetTokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "knowledgeCollectionStorageContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "knowledgeCollectionTokenId", + "type": "uint256" + } + ], + "name": "submitKnowledgeCollection", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "paranetKCStorageContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "internalType": "uint256", "name": "paranetKATokenId", @@ -1297,9 +1595,14 @@ "inputs": [ { "internalType": "address", - "name": "paranetServiceKAStorageContract", + "name": "paranetServiceKCStorageContract", "type": "address" }, + { + "internalType": "uint256", + "name": "paranetServiceKCTokenId", + "type": "uint256" + }, { "internalType": "uint256", "name": "paranetServiceKATokenId", diff --git a/dkg/data/interfaces/ParanetIncentivesPoolFactory.json b/dkg/data/interfaces/ParanetIncentivesPoolFactory.json index 774b229..9d86e09 100644 --- a/dkg/data/interfaces/ParanetIncentivesPoolFactory.json +++ b/dkg/data/interfaces/ParanetIncentivesPoolFactory.json @@ -14,12 +14,17 @@ "inputs": [ { "internalType": "address", - "name": "knowledgeAssetStorageAddress", + "name": "knowledgeCollectionStorageAddress", "type": "address" }, { "internalType": "uint256", - "name": "tokenId", + "name": "knowledgeCollectionTokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "knowledgeAssetTokenId", "type": "uint256" }, { @@ -58,13 +63,13 @@ { "indexed": true, "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, { "indexed": true, "internalType": "uint256", - "name": "paranetKATokenId", + "name": "paranetKCTokenId", "type": "uint256" }, { @@ -91,11 +96,21 @@ }, { "inputs": [ + { + "internalType": "bool", + "name": "isNativeReward", + "type": "bool" + }, { "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "internalType": "uint256", "name": "paranetKATokenId", diff --git a/dkg/data/interfaces/ParanetKnowledgeCollectionsRegistry.json b/dkg/data/interfaces/ParanetKnowledgeCollectionsRegistry.json new file mode 100644 index 0000000..7a65424 --- /dev/null +++ b/dkg/data/interfaces/ParanetKnowledgeCollectionsRegistry.json @@ -0,0 +1,304 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "hubAddress", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "msg", + "type": "string" + } + ], + "name": "UnauthorizedAccess", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddressHub", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "paranetId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "knowledgeCollectionStorageContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "knowledgeCollectionTokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "miner", + "type": "address" + } + ], + "name": "addKnowledgeCollection", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "knowledgeCollectionId", + "type": "bytes32" + } + ], + "name": "getKnowledgeCollectionLocator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32[]", + "name": "knowledgeCollectionIds", + "type": "bytes32[]" + } + ], + "name": "getKnowledgeCollectionLocators", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "knowledgeCollectionStorageContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "knowledgeCollectionTokenId", + "type": "uint256" + } + ], + "internalType": "struct ParanetLib.UniversalCollectionLocator[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "knowledgeCollectionId", + "type": "bytes32" + } + ], + "name": "getKnowledgeCollectionObject", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "knowledgeCollectionStorageContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "knowledgeCollectionTokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "minerAddress", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "paranetId", + "type": "bytes32" + } + ], + "internalType": "struct ParanetLib.KnowledgeCollection", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "knowledgeCollectionId", + "type": "bytes32" + } + ], + "name": "getMinerAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "knowledgeCollectionId", + "type": "bytes32" + } + ], + "name": "getParanetId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "hub", + "outputs": [ + { + "internalType": "contract Hub", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "knowledgeCollectionId", + "type": "bytes32" + } + ], + "name": "isParanetKnowledgeCollection", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "knowledgeCollectionId", + "type": "bytes32" + } + ], + "name": "removeKnowledgeCollection", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "knowledgeCollectionId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "minerAddress", + "type": "address" + } + ], + "name": "setMinerAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "knowledgeCollectionId", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "paranetId", + "type": "bytes32" + } + ], + "name": "setParanetId", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + } +] diff --git a/dkg/data/interfaces/ParanetKnowledgeMinersRegistry.json b/dkg/data/interfaces/ParanetKnowledgeMinersRegistry.json index f78c7e5..f77f96f 100644 --- a/dkg/data/interfaces/ParanetKnowledgeMinersRegistry.json +++ b/dkg/data/interfaces/ParanetKnowledgeMinersRegistry.json @@ -86,11 +86,11 @@ }, { "internalType": "bytes32", - "name": "knowledgeAssetId", + "name": "knowledgeCollectionId", "type": "bytes32" } ], - "name": "addSubmittedKnowledgeAsset", + "name": "addSubmittedKnowledgeCollection", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -150,17 +150,17 @@ }, { "internalType": "address", - "name": "knowledgeAssetStorageContract", + "name": "knowledgeCollectionStorageContract", "type": "address" }, { "internalType": "uint256", - "name": "tokenId", + "name": "knowledgeCollectionId", "type": "uint256" }, { "internalType": "bytes32", - "name": "assertionId", + "name": "merkleRoot", "type": "bytes32" }, { @@ -169,7 +169,7 @@ "type": "uint96" } ], - "name": "addUpdatingKnowledgeAssetState", + "name": "addUpdatingKnowledgeCollectionState", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -188,7 +188,7 @@ }, { "internalType": "bytes32", - "name": "knowledgeAssetStateId", + "name": "knowledgeCollectionStateId", "type": "bytes32" }, { @@ -197,7 +197,7 @@ "type": "uint96" } ], - "name": "addUpdatingKnowledgeAssetUpdateTokenAmount", + "name": "addUpdatingKnowledgeCollectionUpdateTokenAmount", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -210,7 +210,7 @@ "type": "address" } ], - "name": "decrementTotalSubmittedKnowledgeAssetsCount", + "name": "decrementTotalSubmittedKnowledgeCollectionsCount", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -300,7 +300,7 @@ }, { "internalType": "uint256", - "name": "totalSubmittedKnowledgeAssetsCount", + "name": "totalSubmittedKnowledgeCollectionsCount", "type": "uint256" } ], @@ -325,7 +325,7 @@ "type": "bytes32" } ], - "name": "getSubmittedKnowledgeAssets", + "name": "getSubmittedKnowledgeCollections", "outputs": [ { "internalType": "bytes32[]", @@ -359,7 +359,7 @@ "type": "uint256" } ], - "name": "getSubmittedKnowledgeAssets", + "name": "getSubmittedKnowledgeCollections", "outputs": [ { "internalType": "bytes32[]", @@ -378,7 +378,7 @@ "type": "address" } ], - "name": "getTotalSubmittedKnowledgeAssetsCount", + "name": "getTotalSubmittedKnowledgeCollectionsCount", "outputs": [ { "internalType": "uint256", @@ -443,35 +443,25 @@ "internalType": "bytes32", "name": "paranetId", "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "start", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "end", - "type": "uint256" } ], - "name": "getUpdatingKnowledgeAssetStates", + "name": "getUpdatingKnowledgeCollectionStates", "outputs": [ { "components": [ { "internalType": "address", - "name": "knowledgeAssetStorageContract", + "name": "knowledgeCollectionStorageContract", "type": "address" }, { "internalType": "uint256", - "name": "tokenId", + "name": "knowledgeCollectionId", "type": "uint256" }, { "internalType": "bytes32", - "name": "assertionId", + "name": "merkleRoot", "type": "bytes32" }, { @@ -480,7 +470,7 @@ "type": "uint96" } ], - "internalType": "struct ParanetLib.UpdatingKnowledgeAssetState[]", + "internalType": "struct ParanetLib.UpdatingKnowledgeCollectionState[]", "name": "", "type": "tuple[]" } @@ -499,25 +489,35 @@ "internalType": "bytes32", "name": "paranetId", "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "start", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "end", + "type": "uint256" } ], - "name": "getUpdatingKnowledgeAssetStates", + "name": "getUpdatingKnowledgeCollectionStates", "outputs": [ { "components": [ { "internalType": "address", - "name": "knowledgeAssetStorageContract", + "name": "knowledgeCollectionStorageContract", "type": "address" }, { "internalType": "uint256", - "name": "tokenId", + "name": "knowledgeCollectionId", "type": "uint256" }, { "internalType": "bytes32", - "name": "assertionId", + "name": "merkleRoot", "type": "bytes32" }, { @@ -526,7 +526,7 @@ "type": "uint96" } ], - "internalType": "struct ParanetLib.UpdatingKnowledgeAssetState[]", + "internalType": "struct ParanetLib.UpdatingKnowledgeCollectionState[]", "name": "", "type": "tuple[]" } @@ -555,7 +555,7 @@ "type": "address" } ], - "name": "incrementTotalSubmittedKnowledgeAssetsCount", + "name": "incrementTotalSubmittedKnowledgeCollectionsCount", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -639,34 +639,11 @@ }, { "internalType": "bytes32", - "name": "knowledgeAssetId", - "type": "bytes32" - } - ], - "name": "removeSubmittedKnowledgeAsset", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "miner", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "paranetId", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "knowledgeAssetStateId", + "name": "knowledgeCollectionId", "type": "bytes32" } ], - "name": "removeUpdatingKnowledgeAssetState", + "name": "removeSubmittedKnowledgeCollection", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -726,11 +703,11 @@ }, { "internalType": "uint256", - "name": "totalSubmittedKnowledgeAssetsCount", + "name": "totalSubmittedKnowledgeCollectionsCount", "type": "uint256" } ], - "name": "setTotalSubmittedKnowledgeAssetsCount", + "name": "setTotalSubmittedKnowledgeCollectionsCount", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -790,7 +767,7 @@ }, { "internalType": "bytes32", - "name": "knowledgeAssetStateId", + "name": "knowledgeCollectionStateId", "type": "bytes32" }, { @@ -799,7 +776,7 @@ "type": "uint96" } ], - "name": "setUpdatingKnowledgeAssetUpdateTokenAmount", + "name": "setUpdatingKnowledgeCollectionUpdateTokenAmount", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -905,7 +882,7 @@ }, { "internalType": "bytes32", - "name": "knowledgeAssetStateId", + "name": "knowledgeCollectionStateId", "type": "bytes32" }, { @@ -914,7 +891,7 @@ "type": "uint96" } ], - "name": "subUpdatingKnowledgeAssetUpdateTokenAmount", + "name": "subUpdatingKnowledgeCollectionUpdateTokenAmount", "outputs": [], "stateMutability": "nonpayable", "type": "function" diff --git a/dkg/data/interfaces/ParanetNeuroIncentivesPool.json b/dkg/data/interfaces/ParanetNeuroIncentivesPool.json index 1677d83..41e2942 100644 --- a/dkg/data/interfaces/ParanetNeuroIncentivesPool.json +++ b/dkg/data/interfaces/ParanetNeuroIncentivesPool.json @@ -6,6 +6,11 @@ "name": "hubAddress", "type": "address" }, + { + "internalType": "address", + "name": "rewardTokenAddress", + "type": "address" + }, { "internalType": "address", "name": "paranetsRegistryAddress", @@ -924,6 +929,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "token", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "totalMinersClaimedNeuro", diff --git a/dkg/data/interfaces/ParanetServicesRegistry.json b/dkg/data/interfaces/ParanetServicesRegistry.json new file mode 100644 index 0000000..3501f26 --- /dev/null +++ b/dkg/data/interfaces/ParanetServicesRegistry.json @@ -0,0 +1,382 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "hubAddress", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "msg", + "type": "string" + } + ], + "name": "UnauthorizedAccess", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddressHub", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "paranetServiceId", + "type": "bytes32" + } + ], + "name": "deleteParanetService", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "paranetServiceId", + "type": "bytes32" + } + ], + "name": "getDescription", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "paranetServiceId", + "type": "bytes32" + } + ], + "name": "getName", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "paranetServiceId", + "type": "bytes32" + } + ], + "name": "getParanetServiceAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "paranetServiceId", + "type": "bytes32" + } + ], + "name": "getParanetServiceKnowledgeCollectionLocator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "paranetServiceId", + "type": "bytes32" + } + ], + "name": "getParanetServiceMetadata", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "paranetServiceKCStorageContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "paranetServiceKCTokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "paranetServiceKATokenId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "internalType": "address[]", + "name": "paranetServiceAddresses", + "type": "address[]" + } + ], + "internalType": "struct ParanetLib.ParanetServiceMetadata", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "hub", + "outputs": [ + { + "internalType": "contract Hub", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "paranetServiceId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "paranetServiceAddress", + "type": "address" + } + ], + "name": "isParanetServiceAddressRegistered", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "paranetServiceId", + "type": "bytes32" + } + ], + "name": "paranetServiceExists", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "paranetServiceKCStorageContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "paranetServiceKCTokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "paranetServiceKATokenId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "paranetServiceName", + "type": "string" + }, + { + "internalType": "string", + "name": "paranetServiceDescription", + "type": "string" + }, + { + "internalType": "address[]", + "name": "paranetServiceAddresses", + "type": "address[]" + } + ], + "name": "registerParanetService", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "paranetServiceId", + "type": "bytes32" + }, + { + "internalType": "string", + "name": "description_", + "type": "string" + } + ], + "name": "setDescription", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "paranetServiceId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "paranetServiceAddress", + "type": "address" + }, + { + "internalType": "bool", + "name": "isRegistered", + "type": "bool" + } + ], + "name": "setIsParanetServiceAddressRegistered", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "paranetServiceId", + "type": "bytes32" + }, + { + "internalType": "string", + "name": "name_", + "type": "string" + } + ], + "name": "setName", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "paranetServiceId", + "type": "bytes32" + }, + { + "internalType": "address[]", + "name": "paranetServiceAddresses", + "type": "address[]" + } + ], + "name": "setParanetServiceAddresses", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + } +] diff --git a/dkg/data/interfaces/ParanetsRegistry.json b/dkg/data/interfaces/ParanetsRegistry.json index 438a9fb..274a860 100644 --- a/dkg/data/interfaces/ParanetsRegistry.json +++ b/dkg/data/interfaces/ParanetsRegistry.json @@ -130,11 +130,11 @@ }, { "internalType": "bytes32", - "name": "knowledgeAssetId", + "name": "knowledgeCollectionId", "type": "bytes32" } ], - "name": "addKnowledgeAsset", + "name": "addKnowledgeCollecton", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -265,6 +265,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "getAllParanetIds", + "outputs": [ + { + "internalType": "bytes32[]", + "name": "", + "type": "bytes32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -385,7 +398,7 @@ "type": "bytes32" } ], - "name": "getKnowledgeAssets", + "name": "getKnowledgeCollections", "outputs": [ { "internalType": "bytes32[]", @@ -404,10 +417,10 @@ "type": "bytes32" } ], - "name": "getKnowledgeAssetsAccessPolicy", + "name": "getKnowledgeCollectionsAccessPolicy", "outputs": [ { - "internalType": "enum ParanetLib.KnowledgeAssetsAccessPolicy", + "internalType": "enum ParanetLib.KnowledgeCollectionsAccessPolicy", "name": "", "type": "uint8" } @@ -423,7 +436,7 @@ "type": "bytes32" } ], - "name": "getKnowledgeAssetsCount", + "name": "getKnowledgeCollectionsCount", "outputs": [ { "internalType": "uint256", @@ -443,7 +456,7 @@ }, { "internalType": "bytes32", - "name": "knowledgeAssetId", + "name": "knowledgeCollectionId", "type": "bytes32" }, { @@ -452,7 +465,7 @@ "type": "uint256" } ], - "name": "getKnowledgeAssetsStartingFromKnowledgeAssetId", + "name": "getKnowledgeCollectionsStartingFromKnowlCollectionId", "outputs": [ { "internalType": "bytes32[]", @@ -481,7 +494,7 @@ "type": "uint256" } ], - "name": "getKnowledgeAssetsWithPagination", + "name": "getKnowledgeCollectionsWithPagination", "outputs": [ { "internalType": "bytes32[]", @@ -921,6 +934,68 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "getParanetIdAtIndex", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "offset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + } + ], + "name": "getParanetIds", + "outputs": [ + { + "internalType": "bytes32[]", + "name": "", + "type": "bytes32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "paranetId", + "type": "bytes32" + } + ], + "name": "getParanetIdsMapping", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -936,6 +1011,11 @@ "name": "", "type": "address" }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, { "internalType": "uint256", "name": "", @@ -959,9 +1039,14 @@ "components": [ { "internalType": "address", - "name": "paranetKAStorageContract", + "name": "paranetKCStorageContract", "type": "address" }, + { + "internalType": "uint256", + "name": "paranetKCTokenId", + "type": "uint256" + }, { "internalType": "uint256", "name": "paranetKATokenId", @@ -988,8 +1073,8 @@ "type": "uint8" }, { - "internalType": "enum ParanetLib.KnowledgeAssetsAccessPolicy", - "name": "knowledgeAssetsAccessPolicy", + "internalType": "enum ParanetLib.KnowledgeCollectionsAccessPolicy", + "name": "knowledgeCollectionsAccessPolicy", "type": "uint8" }, { @@ -1006,6 +1091,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "getParanetsCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1138,11 +1236,11 @@ }, { "internalType": "bytes32", - "name": "knowledgeAssetId", + "name": "knowledgeCollectionId", "type": "bytes32" } ], - "name": "isKnowledgeAssetRegistered", + "name": "isKnowledgeCollectionRegistered", "outputs": [ { "internalType": "bool", @@ -1237,12 +1335,17 @@ "inputs": [ { "internalType": "address", - "name": "knowledgeAssetStorageContract", + "name": "knowledgeCollectionStorageContract", "type": "address" }, { "internalType": "uint256", - "name": "tokenId", + "name": "knowledgeCollectionTokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "knowledgeAssetTokenId", "type": "uint256" }, { @@ -1266,8 +1369,8 @@ "type": "uint8" }, { - "internalType": "enum ParanetLib.KnowledgeAssetsAccessPolicy", - "name": "knowledgeAssetsAccessPolicy", + "internalType": "enum ParanetLib.KnowledgeCollectionsAccessPolicy", + "name": "knowledgeColletionsAccessPolicy", "type": "uint8" } ], @@ -1345,11 +1448,11 @@ }, { "internalType": "bytes32", - "name": "knowledgeAssetId", + "name": "knowledgeCollectionId", "type": "bytes32" } ], - "name": "removeKnowledgeAsset", + "name": "removeKnowledgeCollection", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -1503,12 +1606,12 @@ "type": "bytes32" }, { - "internalType": "enum ParanetLib.KnowledgeAssetsAccessPolicy", - "name": "knowledgeAssetsAccessPolicy", + "internalType": "enum ParanetLib.KnowledgeCollectionsAccessPolicy", + "name": "knowledgeCollectionsAccessPolicy", "type": "uint8" } ], - "name": "setKnowledgeAssetsAccessPolicy", + "name": "setKnowledgeCollectionsAccessPolicy", "outputs": [], "stateMutability": "nonpayable", "type": "function" diff --git a/dkg/dataclasses.py b/dkg/dataclasses.py index 67c9b5f..ff98d01 100644 --- a/dkg/dataclasses.py +++ b/dkg/dataclasses.py @@ -16,11 +16,11 @@ # under the License. from dataclasses import dataclass -from enum import auto, Enum, IntEnum +from enum import auto, Enum, IntEnum, StrEnum import pandas as pd -from dkg.types import AutoStrEnum, AutoStrEnumCapitalize, AutoStrEnumUpperCase +from dkg.types import AutoStrEnumUpperCase class BlockchainResponseDict(dict): @@ -37,13 +37,6 @@ def to_dataframe(self) -> pd.DataFrame: return pd.DataFrame(self) -class BidSuggestionRange(AutoStrEnum): - LOW = auto() - MEDIUM = auto() - HIGH = auto() - ALL = auto() - - class KnowledgeAssetEnumStates(AutoStrEnumUpperCase): LATEST = auto() LATEST_FINALIZED = auto() @@ -55,8 +48,9 @@ class KnowledgeAssetContentVisibility(AutoStrEnumUpperCase): PRIVATE = auto() -class ParanetIncentivizationType(AutoStrEnumCapitalize): - NEUROWEB = auto() +class ParanetIncentivizationType(StrEnum): + NEUROWEB = "Neuroweb" + NEUROWEB_ERC20 = "NeurowebERC20" class ParanetNodesAccessPolicy(IntEnum): diff --git a/dkg/managers/async_manager.py b/dkg/managers/async_manager.py index 67ea01a..5edd8d2 100644 --- a/dkg/managers/async_manager.py +++ b/dkg/managers/async_manager.py @@ -19,8 +19,8 @@ from dkg.dataclasses import BlockchainResponseDict, NodeResponseDict from dkg.exceptions import InvalidRequest -from dkg.utils.blockchain_request import ContractInteraction, JSONRPCRequest -from dkg.utils.node_request import NodeCall +from dkg.request_managers.blockchain_request import ContractInteraction, JSONRPCRequest +from dkg.request_managers.node_request import NodeCall from dkg.providers.node.async_node_http import AsyncNodeHTTPProvider from dkg.providers.blockchain.async_blockchain import AsyncBlockchainProvider diff --git a/dkg/managers/manager.py b/dkg/managers/manager.py index 922d15c..bf9c880 100644 --- a/dkg/managers/manager.py +++ b/dkg/managers/manager.py @@ -20,8 +20,8 @@ from dkg.dataclasses import BlockchainResponseDict, NodeResponseDict from dkg.exceptions import InvalidRequest from dkg.providers import BlockchainProvider, NodeHTTPProvider -from dkg.utils.blockchain_request import ContractInteraction, JSONRPCRequest -from dkg.utils.node_request import NodeCall +from dkg.request_managers.blockchain_request import ContractInteraction, JSONRPCRequest +from dkg.request_managers.node_request import NodeCall class DefaultRequestManager: diff --git a/dkg/method.py b/dkg/method.py index 5e7f517..d89adc9 100644 --- a/dkg/method.py +++ b/dkg/method.py @@ -21,13 +21,13 @@ from dkg.exceptions import ValidationError from dkg.types import TFunc -from dkg.utils.blockchain_request import ( +from dkg.request_managers.blockchain_request import ( ContractInteraction, ContractTransaction, JSONRPCRequest, ) -from dkg.utils.node_request import NodeCall -from dkg.utils.string_transformations import snake_to_camel +from dkg.request_managers.node_request import NodeCall +from dkg.utils.common import snake_to_camel if TYPE_CHECKING: from dkg.modules.module import Module diff --git a/dkg/modules/asset/asset.py b/dkg/modules/asset/asset.py index 90d5ccd..b70ee44 100644 --- a/dkg/modules/asset/asset.py +++ b/dkg/modules/asset/asset.py @@ -16,17 +16,10 @@ # under the License. import json -import hashlib from typing import Literal -from pyld import jsonld from web3 import Web3 -from web3.constants import ADDRESS_ZERO from web3.types import TxReceipt from itertools import chain -from eth_abi.packed import encode_packed -from eth_account.messages import encode_defunct -from eth_account import Account -from hexbytes import HexBytes from dkg.constants import ( PRIVATE_ASSERTION_PREDICATE, @@ -42,23 +35,18 @@ NodeResponseDict, ) from dkg.managers.manager import DefaultRequestManager -from dkg.method import Method from dkg.modules.module import Module from dkg.types import JSONLD, UAL, Address, HexStr -from dkg.utils.blockchain_request import ( - BlockchainRequest, -) -from dkg.utils.node_request import ( - NodeRequest, +from dkg.request_managers.node_request import ( OperationStatus, get_operation_status_object, ) -from dkg.utils.ual import format_ual, parse_ual +from dkg.utils.ual import format_ual, parse_ual, get_paranet_ual_details, get_paranet_id import dkg.utils.knowledge_collection_tools as kc_tools -import dkg.utils.knowledge_asset_tools as ka_tools from dkg.services.input_service import InputService from dkg.services.node_services.node_service import NodeService from dkg.services.blockchain_services.blockchain_service import BlockchainService +from dkg.utils.common import get_operation_status_dict, get_message_signer_address class KnowledgeAsset(Module): @@ -74,82 +62,70 @@ def __init__( self.node_service = node_service self.blockchain_service = blockchain_service - def is_valid_ual(self, ual: UAL) -> bool: - if not ual or not isinstance(ual, str): - raise ValueError("UAL must be a non-empty string.") - - parts = ual.split("/") - if len(parts) != 3: - raise ValueError("UAL format is incorrect.") - - prefixes = parts[0].split(":") - prefixes_number = len(prefixes) - if prefixes_number != 3 and prefixes_number != 4: - raise ValueError("Prefix format in UAL is incorrect.") - - if prefixes[0] != "did": - raise ValueError( - f"Invalid DID prefix. Expected: 'did'. Received: '{prefixes[0]}'." - ) - - if prefixes[1] != "dkg": - raise ValueError( - f"Invalid DKG prefix. Expected: 'dkg'. Received: '{prefixes[1]}'." - ) + # def is_valid_ual(self, ual: UAL) -> bool: + # if not ual or not isinstance(ual, str): + # raise ValueError("UAL must be a non-empty string.") - if prefixes[2] != ( - blockchain_name := ( - self.manager.blockchain_provider.blockchain_id.split(":")[0] - ) - ): - raise ValueError( - "Invalid blockchain name in the UAL prefix. " - f"Expected: '{blockchain_name}'. Received: '${prefixes[2]}'." - ) + # parts = ual.split("/") + # if len(parts) != 3: + # raise ValueError("UAL format is incorrect.") - if prefixes_number == 4: - chain_id = self.manager.blockchain_provider.blockchain_id.split(":")[1] + # prefixes = parts[0].split(":") + # prefixes_number = len(prefixes) + # if prefixes_number != 3 and prefixes_number != 4: + # raise ValueError("Prefix format in UAL is incorrect.") - if int(prefixes[3]) != int(chain_id): - raise ValueError( - "Chain ID in UAL does not match the blockchain. " - f"Expected: '${chain_id}'. Received: '${prefixes[3]}'." - ) + # if prefixes[0] != "did": + # raise ValueError( + # f"Invalid DID prefix. Expected: 'did'. Received: '{prefixes[0]}'." + # ) - contract_address = self.manager.blockchain_provider.contracts[ - "ContentAssetStorage" - ].address + # if prefixes[1] != "dkg": + # raise ValueError( + # f"Invalid DKG prefix. Expected: 'dkg'. Received: '{prefixes[1]}'." + # ) - if parts[1].lower() != contract_address.lower(): - raise ValueError( - "Contract address in UAL does not match. " - f"Expected: '${contract_address.lower()}'. " - f"Received: '${parts[1].lower()}'." - ) + # if prefixes[2] != ( + # blockchain_name := ( + # self.manager.blockchain_provider.blockchain_id.split(":")[0] + # ) + # ): + # raise ValueError( + # "Invalid blockchain name in the UAL prefix. " + # f"Expected: '{blockchain_name}'. Received: '${prefixes[2]}'." + # ) - try: - owner = self.blockchain_service.get_owner(int(parts[2])) + # if prefixes_number == 4: + # chain_id = self.manager.blockchain_provider.blockchain_id.split(":")[1] - if not owner or owner == ADDRESS_ZERO: - raise ValueError("Token does not exist or has no owner.") + # if int(prefixes[3]) != int(chain_id): + # raise ValueError( + # "Chain ID in UAL does not match the blockchain. " + # f"Expected: '${chain_id}'. Received: '${prefixes[3]}'." + # ) - return True - except Exception as err: - raise ValueError(f"Error fetching asset owner: {err}") + # contract_address = self.manager.blockchain_provider.contracts[ + # "ContentAssetStorage" + # ].address - def process_content(self, content: str) -> list: - return [line.strip() for line in content.split("\n") if line.strip() != ""] + # if parts[1].lower() != contract_address.lower(): + # raise ValueError( + # "Contract address in UAL does not match. " + # f"Expected: '${contract_address.lower()}'. " + # f"Received: '${parts[1].lower()}'." + # ) - def solidity_packed_sha256(self, types: list[str], values: list) -> str: - # Encode the values using eth_abi's encode_packed - packed_data = encode_packed(types, values) + # try: + # owner = self.blockchain_service.get_owner(int(parts[2])) - # Calculate SHA256 - sha256_hash = hashlib.sha256(packed_data).hexdigest() + # if not owner or owner == ADDRESS_ZERO: + # raise ValueError("Token does not exist or has no owner.") - return f"0x{sha256_hash}" + # return True + # except Exception as err: + # raise ValueError(f"Error fetching asset owner: {err}") - def insert_triple_sorted(self, triples_list: list, new_triple: str) -> int: + def _insert_triple_sorted(self, triples_list: list, new_triple: str) -> int: # Assuming triples_list is already sorted left = 0 right = len(triples_list) @@ -165,27 +141,6 @@ def insert_triple_sorted(self, triples_list: list, new_triple: str) -> int: triples_list.insert(left, new_triple) return left - def get_operation_status_dict(self, operation_result, operation_id): - # Check if data exists and has errorType - operation_data = ( - {"status": operation_result.get("status"), **operation_result.get("data")} - if operation_result.get("data") - and operation_result.get("data", {}).get("errorType") - else {"status": operation_result.get("status")} - ) - - return {"operationId": operation_id, **operation_data} - - def get_message_signer_address(self, dataset_root: str, signature: dict): - message = encode_defunct(HexBytes(dataset_root)) - r, s, v = signature.get("r"), signature.get("s"), signature.get("v") - r = r[2:] if r.startswith("0x") else r - s = s[2:] if s.startswith("0x") else s - - sig = "0x" + r + s + hex(v)[2:].zfill(2) - - return Account.recover_message(message, signature=sig) - def create( self, content: dict[Literal["public", "private"], JSONLD], @@ -212,17 +167,17 @@ def create( public_content = dataset.get("public") private_content = dataset.get("private") if isinstance(content, str): - dataset["public"] = self.process_content(content) + dataset["public"] = kc_tools.process_content(content) elif isinstance(public_content, str) or ( not public_content and private_content and isinstance(private_content, str) ): if public_content: - dataset["public"] = self.process_content(public_content) + dataset["public"] = kc_tools.process_content(public_content) else: dataset["public"] = [] if private_content and isinstance(private_content, str): - dataset["private"] = self.process_content(private_content) + dataset["private"] = kc_tools.process_content(private_content) else: dataset = kc_tools.format_dataset(content) @@ -247,7 +202,7 @@ def create( # Compute private root and add to public private_root = kc_tools.calculate_merkle_root(dataset.get("private")) dataset["public"].append( - f'<{ka_tools.generate_named_node()}> <{PRIVATE_ASSERTION_PREDICATE}> "{private_root}" .' + f'<{kc_tools.generate_named_node()}> <{PRIVATE_ASSERTION_PREDICATE}> "{private_root}" .' ) # Compute private root and add to public @@ -269,7 +224,7 @@ def create( 0 ] # Extract the private subject - private_subject_hash = self.solidity_packed_sha256( + private_subject_hash = kc_tools.solidity_packed_sha256( types=["string"], values=[private_subject[1:-1]], ) @@ -279,15 +234,15 @@ def create( ): # Check if there's a public pair # If there's a public pair, insert a representation in that group public_index = public_subject_dict.get(private_subject) - self.insert_triple_sorted( + self._insert_triple_sorted( public_triples_grouped[public_index], - f"{private_subject} <{PRIVATE_RESOURCE_PREDICATE}> <{ka_tools.generate_named_node()}> .", + f"{private_subject} <{PRIVATE_RESOURCE_PREDICATE}> <{kc_tools.generate_named_node()}> .", ) else: # If no public pair, maintain separate list, inserting sorted by hash - self.insert_triple_sorted( + self._insert_triple_sorted( private_triple_subject_hashes_grouped_without_public_pair, - f"<{PRIVATE_HASH_SUBJECT_PREFIX}{private_subject_hash}> <{PRIVATE_RESOURCE_PREDICATE}> <{ka_tools.generate_named_node()}> .", + f"<{PRIVATE_HASH_SUBJECT_PREFIX}{private_subject_hash}> <{PRIVATE_RESOURCE_PREDICATE}> <{kc_tools.generate_named_node()}> .", ) for triple in private_triple_subject_hashes_grouped_without_public_pair: @@ -343,7 +298,7 @@ def create( return { "datasetRoot": dataset_root, "operation": { - "publish": self.get_operation_status_dict( + "publish": get_operation_status_dict( publish_operation_result, publish_operation_id ) }, @@ -361,9 +316,7 @@ def create( for signature in signatures: try: - signer_address = self.get_message_signer_address( - dataset_root, signature - ) + signer_address = get_message_signer_address(dataset_root, signature) key_is_operational_wallet = ( self.blockchain_service.key_is_operational_wallet( @@ -476,55 +429,53 @@ def create( ) ) - _submit_knowledge_asset = Method(BlockchainRequest.submit_knowledge_asset) - def submit_to_paranet( self, ual: UAL, paranet_ual: UAL ) -> dict[str, UAL | Address | TxReceipt]: parsed_ual = parse_ual(ual) - knowledge_asset_storage, knowledge_asset_token_id = ( + knowledge_collection_storage, knowledge_collection_token_id = ( parsed_ual["contract_address"], - parsed_ual["token_id"], + parsed_ual["knowledge_collection_token_id"], ) - parsed_paranet_ual = parse_ual(paranet_ual) - paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id = ( - parsed_paranet_ual["contract_address"], - parsed_paranet_ual["token_id"], - ) + ( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + ) = get_paranet_ual_details(paranet_ual) - receipt: TxReceipt = self._submit_knowledge_asset( - paranet_knowledge_asset_storage, + receipt: TxReceipt = self.blockchain_service.submit_knowledge_collection( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, paranet_knowledge_asset_token_id, - knowledge_asset_storage, - knowledge_asset_token_id, + knowledge_collection_storage, + knowledge_collection_token_id, ) return { "UAL": ual, "paranetUAL": paranet_ual, - "paranetId": Web3.to_hex( - Web3.solidity_keccak( - ["address", "uint256"], - [knowledge_asset_storage, knowledge_asset_token_id], - ) - ), + "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), "operation": json.loads(Web3.to_json(receipt)), } - _transfer = Method(BlockchainRequest.transfer_asset) + # _transfer = Method(BlockchainRequest.transfer_asset) def transfer( self, ual: UAL, new_owner: Address, ) -> dict[str, UAL | Address | TxReceipt]: - token_id = parse_ual(ual)["token_id"] + knowledge_collection_token_id = parse_ual(ual)["knowledge_collection_token_id"] - receipt: TxReceipt = self._transfer( - self.manager.blockchain_provider.account, - new_owner, - token_id, + asset_id = ( + knowledge_collection_token_id - 1 + ) * 1_000_000 + knowledge_collection_token_id + + receipt: TxReceipt = self.blockchain_service.transfer_asset( + from_=self.manager.blockchain_provider.account.address, + to=new_owner, + token_id=asset_id, ) return { @@ -533,19 +484,22 @@ def transfer( "operation": json.loads(Web3.to_json(receipt)), } - _burn_asset = Method(BlockchainRequest.burn_asset) - - def burn(self, ual: UAL) -> dict[str, UAL | TxReceipt]: - token_id = parse_ual(ual)["token_id"] + # def burn(self, ual: UAL, token_ids: list[int]) -> dict[str, UAL | TxReceipt]: + # knowledge_collection_token_id = parse_ual(ual)["knowledge_collection_token_id"] - receipt: TxReceipt = self._burn_asset(token_id) + # # TODO: Rename this in contracts to burnKnowledgeCollections + # receipt: TxReceipt = self.blockchain_service.burn_knowledge_assets_tokens( + # knowledge_collection_token_id, + # self.manager.blockchain_provider.account.address, + # token_ids, + # ) - return {"UAL": ual, "operation": json.loads(Web3.to_json(receipt))} + # return {"UAL": ual, "operation": json.loads(Web3.to_json(receipt))} - _get_latest_assertion_id = Method(BlockchainRequest.get_latest_assertion_id) + # _get_latest_assertion_id = Method(BlockchainRequest.get_latest_assertion_id) - _get = Method(NodeRequest.get) - _query = Method(NodeRequest.query) + # _get = Method(NodeRequest.get) + # _query = Method(NodeRequest.query) def get(self, ual: UAL, options: dict = {}) -> dict: arguments = self.input_service.get_asset_get_arguments(options) @@ -640,17 +594,17 @@ def get(self, ual: UAL, options: dict = {}) -> dict: formatted_metadata = None if output_format == OutputTypes.JSONLD.value: - formatted_assertion = self.to_jsonld(formatted_assertion) + formatted_assertion = kc_tools.to_jsonld(formatted_assertion) if include_metadata: - formatted_metadata = self.to_jsonld("\n".join(metadata)) + formatted_metadata = kc_tools.to_jsonld("\n".join(metadata)) if output_format == OutputTypes.NQUADS.value: - formatted_assertion = self.to_nquads( + formatted_assertion = kc_tools.to_nquads( formatted_assertion, DEFAULT_RDF_FORMAT ) if include_metadata: - formatted_metadata = self.to_nquads( + formatted_metadata = kc_tools.to_nquads( "\n".join(metadata), DEFAULT_RDF_FORMAT ) @@ -710,30 +664,4 @@ def get(self, ual: UAL, options: dict = {}) -> dict: # "operation": json.loads(Web3.to_json(receipt)), # } - _get_assertion_size = Method(BlockchainRequest.get_assertion_size) - - def to_jsonld(self, nquads: str): - options = { - "algorithm": "URDNA2015", - "format": "application/n-quads", - } - - return jsonld.from_rdf(nquads, options) - - def to_nquads(self, content, input_format): - options = { - "algorithm": "URDNA2015", - "format": "application/n-quads", - } - - if input_format: - options["inputFormat"] = input_format - try: - jsonld_data = jsonld.from_rdf(content, options) - canonized = jsonld.to_rdf(jsonld_data, options) - - if isinstance(canonized, str): - return [line for line in canonized.split("\n") if line.strip()] - - except Exception as e: - raise ValueError(f"Error processing content: {e}") + # _get_assertion_size = Method(BlockchainRequest.get_assertion_size) diff --git a/dkg/modules/asset/async_asset.py b/dkg/modules/asset/async_asset.py index 939b539..3564f45 100644 --- a/dkg/modules/asset/async_asset.py +++ b/dkg/modules/asset/async_asset.py @@ -18,14 +18,9 @@ import json import asyncio from typing import Literal -from pyld import jsonld from web3 import Web3 -from web3.constants import ADDRESS_ZERO from web3.types import TxReceipt from itertools import chain -from eth_account.messages import encode_defunct -from eth_account import Account -from hexbytes import HexBytes from dkg.constants import ( PRIVATE_ASSERTION_PREDICATE, @@ -38,24 +33,20 @@ OutputTypes, ) from dkg.managers.async_manager import AsyncRequestManager -from dkg.method import Method from dkg.modules.async_module import AsyncModule from dkg.types import JSONLD, UAL, Address, HexStr -from dkg.utils.blockchain_request import ( - BlockchainRequest, -) -from dkg.utils.node_request import ( +from dkg.request_managers.node_request import ( OperationStatus, + get_operation_status_object, ) -from dkg.utils.ual import format_ual, parse_ual +from dkg.utils.ual import format_ual, parse_ual, get_paranet_ual_details, get_paranet_id import dkg.utils.knowledge_collection_tools as kc_tools -import dkg.utils.knowledge_asset_tools as ka_tools from dkg.services.input_service import InputService from dkg.services.node_services.async_node_service import AsyncNodeService from dkg.services.blockchain_services.async_blockchain_service import ( AsyncBlockchainService, ) -from dkg.utils.node_request import get_operation_status_object +from dkg.utils.common import get_operation_status_dict, get_message_signer_address class AsyncKnowledgeAsset(AsyncModule): @@ -71,73 +62,71 @@ def __init__( self.node_service = node_service self.blockchain_service = blockchain_service - async def is_valid_ual(self, ual: UAL) -> bool: - if not ual or not isinstance(ual, str): - raise ValueError("UAL must be a non-empty string.") - - parts = ual.split("/") - if len(parts) != 3: - raise ValueError("UAL format is incorrect.") + # async def is_valid_ual(self, ual: UAL) -> bool: + # if not ual or not isinstance(ual, str): + # raise ValueError("UAL must be a non-empty string.") - prefixes = parts[0].split(":") - prefixes_number = len(prefixes) - if prefixes_number != 3 and prefixes_number != 4: - raise ValueError("Prefix format in UAL is incorrect.") + # parts = ual.split("/") + # if len(parts) != 3: + # raise ValueError("UAL format is incorrect.") - if prefixes[0] != "did": - raise ValueError( - f"Invalid DID prefix. Expected: 'did'. Received: '{prefixes[0]}'." - ) + # prefixes = parts[0].split(":") + # prefixes_number = len(prefixes) + # if prefixes_number != 3 and prefixes_number != 4: + # raise ValueError("Prefix format in UAL is incorrect.") - if prefixes[1] != "dkg": - raise ValueError( - f"Invalid DKG prefix. Expected: 'dkg'. Received: '{prefixes[1]}'." - ) + # if prefixes[0] != "did": + # raise ValueError( + # f"Invalid DID prefix. Expected: 'did'. Received: '{prefixes[0]}'." + # ) - if prefixes[2] != ( - blockchain_name := ( - self.manager.blockchain_provider.blockchain_id.split(":")[0] - ) - ): - raise ValueError( - "Invalid blockchain name in the UAL prefix. " - f"Expected: '{blockchain_name}'. Received: '${prefixes[2]}'." - ) + # if prefixes[1] != "dkg": + # raise ValueError( + # f"Invalid DKG prefix. Expected: 'dkg'. Received: '{prefixes[1]}'." + # ) - if prefixes_number == 4: - chain_id = self.manager.blockchain_provider.blockchain_id.split(":")[1] + # if prefixes[2] != ( + # blockchain_name := ( + # self.manager.blockchain_provider.blockchain_id.split(":")[0] + # ) + # ): + # raise ValueError( + # "Invalid blockchain name in the UAL prefix. " + # f"Expected: '{blockchain_name}'. Received: '${prefixes[2]}'." + # ) - if int(prefixes[3]) != int(chain_id): - raise ValueError( - "Chain ID in UAL does not match the blockchain. " - f"Expected: '${chain_id}'. Received: '${prefixes[3]}'." - ) + # if prefixes_number == 4: + # chain_id = self.manager.blockchain_provider.blockchain_id.split(":")[1] - contract_address = self.manager.blockchain_provider.contracts[ - "ContentAssetStorage" - ].address + # if int(prefixes[3]) != int(chain_id): + # raise ValueError( + # "Chain ID in UAL does not match the blockchain. " + # f"Expected: '${chain_id}'. Received: '${prefixes[3]}'." + # ) - if parts[1].lower() != contract_address.lower(): - raise ValueError( - "Contract address in UAL does not match. " - f"Expected: '${contract_address.lower()}'. " - f"Received: '${parts[1].lower()}'." - ) + # contract_address = self.manager.blockchain_provider.contracts[ + # "ContentAssetStorage" + # ].address - try: - owner = await self.blockchain_service.get_owner(int(parts[2])) + # if parts[1].lower() != contract_address.lower(): + # raise ValueError( + # "Contract address in UAL does not match. " + # f"Expected: '${contract_address.lower()}'. " + # f"Received: '${parts[1].lower()}'." + # ) - if not owner or owner == ADDRESS_ZERO: - raise ValueError("Token does not exist or has no owner.") + # try: + # owner = await self.blockchain_service.get_owner(int(parts[2])) - return True - except Exception as err: - raise ValueError(f"Error fetching asset owner: {err}") + # if not owner or owner == ADDRESS_ZERO: + # raise ValueError("Token does not exist or has no owner.") - def process_content(self, content: str) -> list: - return [line.strip() for line in content.split("\n") if line.strip() != ""] + # return True + # except Exception as err: + # raise ValueError(f"Error fetching asset owner: {err}") - def insert_triple_sorted(self, triples_list: list, new_triple: str) -> int: + # TODO: Rewrite this + def _insert_triple_sorted(self, triples_list: list, new_triple: str) -> int: # Assuming triples_list is already sorted left = 0 right = len(triples_list) @@ -153,33 +142,10 @@ def insert_triple_sorted(self, triples_list: list, new_triple: str) -> int: triples_list.insert(left, new_triple) return left - def get_operation_status_dict(self, operation_result, operation_id): - # Check if data exists and has errorType - operation_data = ( - {"status": operation_result.get("status"), **operation_result.get("data")} - if operation_result.get("data") - and operation_result.get("data", {}).get("errorType") - else {"status": operation_result.get("status")} - ) - - return {"operationId": operation_id, **operation_data} - - def get_message_signer_address(self, dataset_root: str, signature: dict): - message = encode_defunct(HexBytes(dataset_root)) - r, s, v = signature.get("r"), signature.get("s"), signature.get("v") - r = r[2:] if r.startswith("0x") else r - s = s[2:] if s.startswith("0x") else s - - sig = "0x" + r + s + hex(v)[2:].zfill(2) - - return Account.recover_message(message, signature=sig) - - async def process_signatures(self, signatures, dataset_root): + async def _process_signatures(self, signatures, dataset_root): async def process_signature(signature): try: - signer_address = self.get_message_signer_address( - dataset_root, signature - ) + signer_address = get_message_signer_address(dataset_root, signature) key_is_operational_wallet = ( await self.blockchain_service.key_is_operational_wallet( @@ -243,17 +209,17 @@ async def create( public_content = dataset.get("public") private_content = dataset.get("private") if isinstance(content, str): - dataset["public"] = self.process_content(content) + dataset["public"] = kc_tools.process_content(content) elif isinstance(public_content, str) or ( not public_content and private_content and isinstance(private_content, str) ): if public_content: - dataset["public"] = self.process_content(public_content) + dataset["public"] = kc_tools.process_content(public_content) else: dataset["public"] = [] if private_content and isinstance(private_content, str): - dataset["private"] = self.process_content(private_content) + dataset["private"] = kc_tools.process_content(private_content) else: dataset = kc_tools.format_dataset(content) @@ -278,7 +244,7 @@ async def create( # Compute private root and add to public private_root = kc_tools.calculate_merkle_root(dataset.get("private")) dataset["public"].append( - f'<{ka_tools.generate_named_node()}> <{PRIVATE_ASSERTION_PREDICATE}> "{private_root}" .' + f'<{kc_tools.generate_named_node()}> <{PRIVATE_ASSERTION_PREDICATE}> "{private_root}" .' ) # Compute private root and add to public @@ -310,15 +276,15 @@ async def create( ): # Check if there's a public pair # If there's a public pair, insert a representation in that group public_index = public_subject_dict.get(private_subject) - self.insert_triple_sorted( + self._insert_triple_sorted( public_triples_grouped[public_index], - f"{private_subject} <{PRIVATE_RESOURCE_PREDICATE}> <{ka_tools.generate_named_node()}> .", + f"{private_subject} <{PRIVATE_RESOURCE_PREDICATE}> <{kc_tools.generate_named_node()}> .", ) else: # If no public pair, maintain separate list, inserting sorted by hash - self.insert_triple_sorted( + self._insert_triple_sorted( private_triple_subject_hashes_grouped_without_public_pair, - f"<{PRIVATE_HASH_SUBJECT_PREFIX}{private_subject_hash}> <{PRIVATE_RESOURCE_PREDICATE}> <{ka_tools.generate_named_node()}> .", + f"<{PRIVATE_HASH_SUBJECT_PREFIX}{private_subject_hash}> <{PRIVATE_RESOURCE_PREDICATE}> <{kc_tools.generate_named_node()}> .", ) for triple in private_triple_subject_hashes_grouped_without_public_pair: @@ -375,7 +341,7 @@ async def create( return { "datasetRoot": dataset_root, "operation": { - "publish": self.get_operation_status_dict( + "publish": get_operation_status_dict( publish_operation_result, publish_operation_id ) }, @@ -389,7 +355,7 @@ async def create( publisher_node_r = publisher_node_signature.get("r") publisher_node_vs = publisher_node_signature.get("vs") - results = await self.process_signatures(signatures, dataset_root) + results = await self._process_signatures(signatures, dataset_root) identity_ids = results["identity_ids"] r = results["r"] vs = results["vs"] @@ -488,55 +454,51 @@ async def create( ) ) - _submit_knowledge_asset = Method(BlockchainRequest.submit_knowledge_asset) - - def submit_to_paranet( + async def submit_to_paranet( self, ual: UAL, paranet_ual: UAL ) -> dict[str, UAL | Address | TxReceipt]: parsed_ual = parse_ual(ual) - knowledge_asset_storage, knowledge_asset_token_id = ( + knowledge_collection_storage, knowledge_collection_token_id = ( parsed_ual["contract_address"], - parsed_ual["token_id"], + parsed_ual["knowledge_collection_token_id"], ) - parsed_paranet_ual = parse_ual(paranet_ual) - paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id = ( - parsed_paranet_ual["contract_address"], - parsed_paranet_ual["token_id"], - ) + ( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + ) = get_paranet_ual_details(paranet_ual) - receipt: TxReceipt = self._submit_knowledge_asset( - paranet_knowledge_asset_storage, + receipt: TxReceipt = await self.blockchain_service.submit_knowledge_collection( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, paranet_knowledge_asset_token_id, - knowledge_asset_storage, - knowledge_asset_token_id, + knowledge_collection_storage, + knowledge_collection_token_id, ) return { "UAL": ual, "paranetUAL": paranet_ual, - "paranetId": Web3.to_hex( - Web3.solidity_keccak( - ["address", "uint256"], - [knowledge_asset_storage, knowledge_asset_token_id], - ) - ), + "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), "operation": json.loads(Web3.to_json(receipt)), } - _transfer = Method(BlockchainRequest.transfer_asset) - - def transfer( + async def transfer( self, ual: UAL, new_owner: Address, ) -> dict[str, UAL | Address | TxReceipt]: - token_id = parse_ual(ual)["token_id"] + knowledge_collection_token_id = parse_ual(ual)["knowledge_collection_token_id"] + + asset_id = ( + knowledge_collection_token_id - 1 + ) * 1_000_000 + knowledge_collection_token_id - receipt: TxReceipt = self._transfer( - self.manager.blockchain_provider.account, - new_owner, - token_id, + receipt: TxReceipt = await self.blockchain_service.transfer_asset( + from_=self.manager.blockchain_provider.account.address, + to=new_owner, + token_id=asset_id, ) return { @@ -545,16 +507,19 @@ def transfer( "operation": json.loads(Web3.to_json(receipt)), } - _burn_asset = Method(BlockchainRequest.burn_asset) + # async def burn(self, ual: UAL, token_ids: list[int]) -> dict[str, UAL | TxReceipt]: + # knowledge_collection_token_id = parse_ual(ual)["knowledge_collection_token_id"] - def burn(self, ual: UAL) -> dict[str, UAL | TxReceipt]: - token_id = parse_ual(ual)["token_id"] - - receipt: TxReceipt = self._burn_asset(token_id) + # # TODO: Rename this in contracts to burnKnowledgeCollections + # receipt: TxReceipt = await self.blockchain_service.burn_knowledge_assets_tokens( + # knowledge_collection_token_id, + # self.manager.blockchain_provider.account.address, + # token_ids, + # ) - return {"UAL": ual, "operation": json.loads(Web3.to_json(receipt))} + # return {"UAL": ual, "operation": json.loads(Web3.to_json(receipt))} - _get_latest_assertion_id = Method(BlockchainRequest.get_latest_assertion_id) + # _get_latest_assertion_id = Method(BlockchainRequest.get_latest_assertion_id) async def get(self, ual: UAL, options: dict = None) -> dict: if options is None: @@ -652,17 +617,17 @@ async def get(self, ual: UAL, options: dict = None) -> dict: formatted_metadata = None if output_format == OutputTypes.JSONLD.value: - formatted_assertion = self.to_jsonld(formatted_assertion) + formatted_assertion = kc_tools.to_jsonld(formatted_assertion) if include_metadata: - formatted_metadata = self.to_jsonld("\n".join(metadata)) + formatted_metadata = kc_tools.to_jsonld("\n".join(metadata)) if output_format == OutputTypes.NQUADS.value: - formatted_assertion = self.to_nquads( + formatted_assertion = kc_tools.to_nquads( formatted_assertion, DEFAULT_RDF_FORMAT ) if include_metadata: - formatted_metadata = self.to_nquads( + formatted_metadata = kc_tools.to_nquads( "\n".join(metadata), DEFAULT_RDF_FORMAT ) @@ -720,32 +685,4 @@ async def get(self, ual: UAL, options: dict = None) -> dict: # "operation": json.loads(Web3.to_json(receipt)), # } - _get_block = Method(BlockchainRequest.get_block) - - _get_assertion_size = Method(BlockchainRequest.get_assertion_size) - - def to_jsonld(self, nquads: str): - options = { - "algorithm": "URDNA2015", - "format": "application/n-quads", - } - - return jsonld.from_rdf(nquads, options) - - def to_nquads(self, content, input_format): - options = { - "algorithm": "URDNA2015", - "format": "application/n-quads", - } - - if input_format: - options["inputFormat"] = input_format - try: - jsonld_data = jsonld.from_rdf(content, options) - canonized = jsonld.to_rdf(jsonld_data, options) - - if isinstance(canonized, str): - return [line for line in canonized.split("\n") if line.strip()] - - except Exception as e: - raise ValueError(f"Error processing content: {e}") + # _get_assertion_size = Method(BlockchainRequest.get_assertion_size) diff --git a/dkg/modules/graph/graph.py b/dkg/modules/graph/graph.py index 3aa65cc..3230d31 100644 --- a/dkg/modules/graph/graph.py +++ b/dkg/modules/graph/graph.py @@ -40,8 +40,11 @@ def __init__( def query( self, query: str, - options: dict = {}, + options: dict = None, ) -> NQuads: + if options is None: + options = {} + arguments = self.input_service.get_query_arguments(options) max_number_of_retries = arguments.get("max_number_of_retries") diff --git a/dkg/modules/network/network.py b/dkg/modules/network/network.py deleted file mode 100644 index 50ebff7..0000000 --- a/dkg/modules/network/network.py +++ /dev/null @@ -1,61 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at - -# http://www.apache.org/licenses/LICENSE-2.0 - -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -from dkg.constants import DefaultParameters -from dkg.dataclasses import BidSuggestionRange -from dkg.managers.manager import DefaultRequestManager -from dkg.method import Method -from dkg.modules.module import Module -from dkg.types import DataHexStr -from dkg.utils.blockchain_request import BlockchainRequest -from dkg.utils.node_request import NodeRequest - - -class Network(Module): - def __init__(self, manager: DefaultRequestManager): - self.manager = manager - - _get_asset_storage_address = Method(BlockchainRequest.get_asset_storage_address) - - _get_bid_suggestion = Method(NodeRequest.bid_suggestion) - - def get_bid_suggestion( - self, - public_assertion_id: DataHexStr, - size_in_bytes: int, - epochs_number: int, - range: BidSuggestionRange = BidSuggestionRange.LOW, - ) -> int: - content_asset_storage_address = self._get_asset_storage_address( - "ContentAssetStorage" - ) - - response = self._get_bid_suggestion( - self.manager.blockchain_provider.blockchain_id, - epochs_number, - size_in_bytes, - content_asset_storage_address, - public_assertion_id, - DefaultParameters.HASH_FUNCTION_ID.value, - range, - ) - - return ( - int(response["bidSuggestion"]) - if range != BidSuggestionRange.ALL - else response - ) diff --git a/dkg/modules/node/async_node.py b/dkg/modules/node/async_node.py index 6cc834d..4b126db 100644 --- a/dkg/modules/node/async_node.py +++ b/dkg/modules/node/async_node.py @@ -19,7 +19,7 @@ from dkg.managers.async_manager import AsyncRequestManager from dkg.method import Method from dkg.modules.async_module import AsyncModule -from dkg.utils.blockchain_request import BlockchainRequest +from dkg.request_managers.blockchain_request import BlockchainRequest from dkg.types import Address from dkg.services.node_services.async_node_service import AsyncNodeService diff --git a/dkg/modules/node/node.py b/dkg/modules/node/node.py index 54de5f8..0a95021 100644 --- a/dkg/modules/node/node.py +++ b/dkg/modules/node/node.py @@ -19,8 +19,8 @@ from dkg.managers.manager import DefaultRequestManager from dkg.method import Method from dkg.modules.module import Module -from dkg.utils.node_request import NodeRequest -from dkg.utils.blockchain_request import BlockchainRequest +from dkg.request_managers.node_request import NodeRequest +from dkg.request_managers.blockchain_request import BlockchainRequest from dkg.types import Address diff --git a/dkg/modules/paranet/async_paranet.py b/dkg/modules/paranet/async_paranet.py new file mode 100644 index 0000000..77e5a2f --- /dev/null +++ b/dkg/modules/paranet/async_paranet.py @@ -0,0 +1,714 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +import json + +from dataclasses import dataclass +from web3 import Web3 +from web3.types import TxReceipt + +from dkg.dataclasses import ( + BaseIncentivesPoolParams, + ParanetIncentivizationType, +) +from dkg.managers.async_manager import AsyncRequestManager +from dkg.modules.async_module import AsyncModule +from dkg.types import Address, UAL, HexStr +from dkg.utils.ual import parse_ual, get_paranet_id, get_paranet_ual_details +from dkg.services.input_service import InputService +from dkg.services.blockchain_services.async_blockchain_service import ( + AsyncBlockchainService, +) +from dkg.exceptions import ValidationError +from dkg.constants import BlockchainIds + + +class AsyncParanet(AsyncModule): + @dataclass + class NeuroWebIncentivesPoolParams(BaseIncentivesPoolParams): + neuro_emission_multiplier: float + operator_percentage: float + voters_percentage: float + + def to_contract_args(self, incentive_type: ParanetIncentivizationType) -> dict: + return { + "trac_to_neuro_emission_multiplier": int( + self.neuro_emission_multiplier + * ( + 10**12 + if incentive_type == ParanetIncentivizationType.NEUROWEB + else 10**18 + ) + ), + "paranet_operator_reward_percentage": int( + self.operator_percentage * 100 + ), + "paranet_incentivization_proposal_voters_reward_percentage": int( + self.voters_percentage * 100 + ), + } + + def __init__( + self, + manager: AsyncRequestManager, + input_service: InputService, + blockchain_service: AsyncBlockchainService, + ): + self.manager = manager + self.input_service = input_service + self.blockchain_service = blockchain_service + self.incentive_type = ( + ParanetIncentivizationType.NEUROWEB + if self.manager.blockchain_provider.blockchain_id + in ( + BlockchainIds.NEUROWEB_DEVNET, + BlockchainIds.NEUROWEB_TESTNET, + BlockchainIds.NEUROWEB_MAINNET, + BlockchainIds.HARDHAT_1, + BlockchainIds.HARDHAT_2, + ) + else ParanetIncentivizationType.NEUROWEB_ERC20 + ) + + async def create( + self, + ual: UAL, + options: dict = {}, + ) -> dict[str, str | HexStr | TxReceipt]: + arguments = self.input_service.get_paranet_create_arguments(options) + name = arguments["paranet_name"] + description = arguments["paranet_description"] + paranet_nodes_access_policy = arguments["paranet_nodes_access_policy"] + paranet_miners_access_policy = arguments["paranet_miners_access_policy"] + + ( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + ) = get_paranet_ual_details(ual) + + receipt: TxReceipt = await self.blockchain_service.register_paranet( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + name, + description, + paranet_nodes_access_policy, + paranet_miners_access_policy, + ) + + return { + "paranetUAL": ual, + "paranetId": Web3.to_hex(get_paranet_id(ual)), + "operation": json.loads(Web3.to_json(receipt)), + } + + # _add_paranet_curated_nodes = Method(BlockchainRequest.add_paranet_curated_nodes) + + # def add_curated_nodes( + # self, paranet_ual: UAL, identity_ids: list[int] + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._add_paranet_curated_nodes( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # identity_ids, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _remove_paranet_curated_nodes = Method( + # BlockchainRequest.remove_paranet_curated_nodes + # ) + + # def remove_curated_nodes( + # self, paranet_ual: UAL, identity_ids: list[int] + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._remove_paranet_curated_nodes( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # identity_ids, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _request_paranet_curated_node_access = Method( + # BlockchainRequest.request_paranet_curated_node_access + # ) + + # def request_curated_node_access( + # self, paranet_ual: UAL + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._request_paranet_curated_node_access( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _approve_curated_node = Method(BlockchainRequest.approve_curated_node) + + # def approve_curated_node( + # self, paranet_ual: UAL, identity_id: int + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._approve_curated_node( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # identity_id, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _reject_curated_node = Method(BlockchainRequest.reject_curated_node) + + # def reject_curated_node( + # self, paranet_ual: UAL, identity_id: int + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._reject_curated_node( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # identity_id, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _get_curated_nodes = Method(BlockchainRequest.get_curated_nodes) + + # def get_curated_nodes( + # self, paranet_ual: UAL + # ) -> dict[str, str | HexStr | TxReceipt]: + # paranet_id = get_paranet_id(paranet_ual) + + # return self._get_curated_nodes(paranet_id) + + # _add_paranet_curated_miners = Method(BlockchainRequest.add_paranet_curated_miners) + + # def add_curated_miners( + # self, paranet_ual: UAL, miner_addresses: list[Address] + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._add_paranet_curated_miners( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # miner_addresses, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _remove_paranet_curated_miners = Method( + # BlockchainRequest.remove_paranet_curated_miners + # ) + + # def remove_curated_miners( + # self, paranet_ual: UAL, miner_addresses: list[Address] + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._remove_paranet_curated_miners( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # miner_addresses, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _request_paranet_curated_miner_access = Method( + # BlockchainRequest.request_paranet_curated_miner_access + # ) + + # def request_curated_miner_access( + # self, paranet_ual: UAL + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._request_paranet_curated_miner_access( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _approve_curated_miner = Method(BlockchainRequest.approve_curated_miner) + + # def approve_curated_miner( + # self, paranet_ual: UAL, miner_address: Address + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._approve_curated_miner( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # miner_address, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _reject_curated_miner = Method(BlockchainRequest.reject_curated_miner) + + # def reject_curated_miner( + # self, paranet_ual: UAL, miner_address: Address + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._reject_curated_miner( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # miner_address, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _get_knowledge_miners = Method(BlockchainRequest.get_knowledge_miners) + + def get_knowledge_miners( + self, paranet_ual: UAL + ) -> dict[str, str | HexStr | TxReceipt]: + paranet_id = get_paranet_id(paranet_ual) + + return self._get_knowledge_miners(paranet_id) + + async def deploy_incentives_contract( + self, + paranet_ual: UAL, + incentives_pool_parameters: NeuroWebIncentivesPoolParams, + ) -> dict[str, str | HexStr | TxReceipt]: + incentive_types = [item.value for item in ParanetIncentivizationType] + if self.incentive_type in incentive_types: + ( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + ) = get_paranet_ual_details(paranet_ual) + + is_native_reward = ( + True + if self.incentive_type == ParanetIncentivizationType.NEUROWEB + else False + ) + + receipt: TxReceipt = await self.blockchain_service.deploy_neuro_incentives_pool( + is_native_reward=is_native_reward, + paranet_knowledge_collection_storage=paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id=paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id=paranet_knowledge_asset_token_id, + **incentives_pool_parameters.to_contract_args(self.incentive_type), + ) + + events = self.manager.blockchain_provider.decode_logs_event( + receipt, + "ParanetIncentivesPoolFactory", + "ParanetIncetivesPoolDeployed", + ) + + return { + "paranetUAL": paranet_ual, + "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + "incentivesPoolContractAddress": events[0].args["incentivesPool"][ + "addr" + ], + "operation": json.loads(Web3.to_json(receipt)), + } + + raise ValueError( + f"{self.incentive_type} Incentive Type isn't supported. Supported " + f"Incentive Types: {incentive_types}" + ) + + async def get_incentives_pool_address( + self, + paranet_ual: UAL, + ) -> Address: + paranet_id = get_paranet_id(paranet_ual) + + return await self.blockchain_service.get_incentives_pool_address( + paranet_id, self.incentive_type + ) + + async def create_service( + self, ual: UAL, options: dict = {} + ) -> dict[str, str | HexStr | TxReceipt]: + arguments = self.input_service.get_paranet_create_service_arguments(options) + paranet_service_name = arguments["paranet_service_name"] + paranet_service_description = arguments["paranet_service_description"] + paranet_service_addresses = arguments["paranet_service_addresses"] + + parsed_ual = parse_ual(ual) + knowledge_collection_storage, knowledge_collection_token_id = ( + parsed_ual["contract_address"], + parsed_ual["knowledge_collection_token_id"], + ) + knowledge_asset_token_id = parsed_ual.get("knowledge_asset_token_id", None) + + if not knowledge_asset_token_id: + raise ValidationError( + "Invalid paranet service UAL! Knowledge asset token id is required!" + ) + + receipt: TxReceipt = await self.blockchain_service.register_paranet_service( + knowledge_collection_storage, + knowledge_collection_token_id, + knowledge_asset_token_id, + paranet_service_name, + paranet_service_description, + paranet_service_addresses, + ) + + return { + "paranetServiceUAL": ual, + "paranetServiceId": Web3.to_hex( + Web3.solidity_keccak( + ["address", "uint256", "uint256"], + [ + knowledge_collection_storage, + knowledge_collection_token_id, + knowledge_asset_token_id, + ], + ) + ), + "operation": json.loads(Web3.to_json(receipt)), + } + + async def add_services( + self, paranet_ual: UAL, services_uals: list[UAL] + ) -> dict[str, str | HexStr | TxReceipt]: + ( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + ) = get_paranet_ual_details(paranet_ual) + + parsed_service_uals = [] + for service_ual in services_uals: + parsed_service_ual = parse_ual(service_ual) + ( + service_knowledge_collection_storage, + service_knowledge_collection_token_id, + service_knowledge_asset_token_id, + ) = ( + parsed_service_ual["contract_address"], + parsed_service_ual["knowledge_collection_token_id"], + parsed_service_ual.get("knowledge_asset_token_id", None), + ) + + if not service_knowledge_asset_token_id: + raise ValidationError( + "Invalid paranet service UAL! Knowledge asset token id is required!" + ) + + parsed_service_uals.append( + [ + service_knowledge_collection_storage, + service_knowledge_collection_token_id, + service_knowledge_asset_token_id, + ] + ) + + receipt: TxReceipt = await self.blockchain_service.add_paranet_services( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + parsed_service_uals, + ) + + return { + "paranetUAL": paranet_ual, + "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + "operation": json.loads(Web3.to_json(receipt)), + } + + async def is_knowledge_miner( + self, + paranet_ual: UAL, + address: Address | None = None, + ) -> bool: + paranet_id = get_paranet_id(paranet_ual) + + return await self.blockchain_service.is_knowledge_miner_registered( + paranet_id, address or self.manager.blockchain_provider.account.address + ) + + async def is_operator( + self, + paranet_ual: UAL, + address: Address | None = None, + ) -> bool: + incentives_pool_address = await self.get_incentives_pool_address(paranet_ual) + + self.blockchain_service.set_incentives_pool(incentives_pool_address) + + return await self.blockchain_service.is_paranet_operator( + operator_address=address or self.manager.blockchain_provider.account.address + ) + + async def is_voter( + self, + paranet_ual: UAL, + address: Address | None = None, + ) -> bool: + incentives_pool_address = await self.get_incentives_pool_address(paranet_ual) + + self.blockchain_service.set_incentives_pool(incentives_pool_address) + + return await self.blockchain_service.is_proposal_voter( + address=address or self.manager.blockchain_provider.account.address, + ) + + # _get_claimable_knowledge_miner_reward_amount = Method( + # BlockchainRequest.get_claimable_knowledge_miner_reward_amount + # ) + + # def calculate_claimable_miner_reward_amount( + # self, + # ual: UAL, + # + # ) -> int: + # return self._get_claimable_knowledge_miner_reward_amount( + # contract=self._get_incentives_pool_contract(ual) + # ) + + # _get_claimable_all_knowledge_miners_reward_amount = Method( + # BlockchainRequest.get_claimable_all_knowledge_miners_reward_amount + # ) + + # def calculate_all_claimable_miner_rewards_amount( + # self, + # ual: UAL, + # + # ) -> int: + # return self._get_claimable_all_knowledge_miners_reward_amount( + # contract=self._get_incentives_pool_contract(ual) + # ) + + # _claim_knowledge_miner_reward = Method( + # BlockchainRequest.claim_knowledge_miner_reward + # ) + + # def claim_miner_reward( + # self, + # ual: UAL, + # + # ) -> dict[str, str | HexStr | TxReceipt]: + # receipt: TxReceipt = self._claim_knowledge_miner_reward( + # contract=self._get_incentives_pool_contract(ual) + # ) + + # paranet_id = get_paranet_id(ual) + + # return { + # "paranetUAL": ual, + # "paranetId": Web3.to_hex(paranet_id), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _get_claimable_paranet_operator_reward_amount = Method( + # BlockchainRequest.get_claimable_paranet_operator_reward_amount + # ) + + # def calculate_claimable_operator_reward_amount( + # self, + # ual: UAL, + # + # ) -> int: + # return self._get_claimable_paranet_operator_reward_amount( + # contract=self._get_incentives_pool_contract(ual) + # ) + + # _claim_paranet_operator_reward = Method( + # BlockchainRequest.claim_paranet_operator_reward + # ) + + # def claim_operator_reward( + # self, + # ual: UAL, + # + # ) -> dict[str, str | HexStr | TxReceipt]: + # receipt: TxReceipt = self._claim_paranet_operator_reward( + # contract=self._get_incentives_pool_contract(ual) + # ) + + # paranet_id = get_paranet_id(ual) + + # return { + # "paranetUAL": ual, + # "paranetId": Web3.to_hex(paranet_id), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _get_claimable_proposal_voter_reward_amount = Method( + # BlockchainRequest.get_claimable_proposal_voter_reward_amount + # ) + + # def calculate_claimable_voter_reward_amount( + # self, + # ual: UAL, + # + # ) -> int: + # return self._get_claimable_proposal_voter_reward_amount( + # contract=self._get_incentives_pool_contract(ual) + # ) + + # _get_claimable_all_proposal_voters_reward_amount = Method( + # BlockchainRequest.get_claimable_all_proposal_voters_reward_amount + # ) + + # def calculate_all_claimable_voters_reward_amount( + # self, + # ual: UAL, + # + # ) -> int: + # return self._get_claimable_all_proposal_voters_reward_amount( + # contract=self._get_incentives_pool_contract(ual) + # ) + + # _claim_incentivization_proposal_voter_reward = Method( + # BlockchainRequest.claim_incentivization_proposal_voter_reward + # ) + + # def claim_voter_reward( + # self, + # ual: UAL, + # + # ) -> dict[str, str | HexStr | TxReceipt]: + # receipt: TxReceipt = self._claim_incentivization_proposal_voter_reward( + # contract=self._get_incentives_pool_contract(ual) + # ) + + # paranet_id = get_paranet_id(ual) + + # return { + # "paranetUAL": ual, + # "paranetId": Web3.to_hex(paranet_id), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # def _get_incentives_pool_contract( + # self, + # ual: UAL, + # ) -> str | dict[str, str]: + # incentives_pool_name = f"Paranet{str(self.incentive_type)}IncentivesPool" + # is_incentives_pool_cached = ( + # incentives_pool_name in self.manager.blockchain_provider.contracts.keys() + # ) + + # return ( + # incentives_pool_name + # if is_incentives_pool_cached + # else { + # "name": incentives_pool_name, + # "address": self.get_incentives_pool_address(ual), + # } + # ) diff --git a/dkg/modules/paranet/paranet.py b/dkg/modules/paranet/paranet.py index b3b4507..1cee5cb 100644 --- a/dkg/modules/paranet/paranet.py +++ b/dkg/modules/paranet/paranet.py @@ -24,15 +24,17 @@ from dkg.dataclasses import ( BaseIncentivesPoolParams, ParanetIncentivizationType, - ParanetNodesAccessPolicy, - ParanetMinersAccessPolicy, ) from dkg.managers.manager import DefaultRequestManager from dkg.method import Method from dkg.modules.module import Module from dkg.types import Address, UAL, HexStr -from dkg.utils.blockchain_request import BlockchainRequest -from dkg.utils.ual import parse_ual +from dkg.request_managers.blockchain_request import BlockchainRequest +from dkg.utils.ual import parse_ual, get_paranet_id, get_paranet_ual_details +from dkg.services.input_service import InputService +from dkg.services.blockchain_services.blockchain_service import BlockchainService +from dkg.exceptions import ValidationError +from dkg.constants import BlockchainIds class Paranet(Module): @@ -42,42 +44,67 @@ class NeuroWebIncentivesPoolParams(BaseIncentivesPoolParams): operator_percentage: float voters_percentage: float - def to_contract_args(self) -> dict: + def to_contract_args(self, incentive_type: ParanetIncentivizationType) -> dict: return { - "tracToNeuroEmissionMultiplier": int( - self.neuro_emission_multiplier * (10**12) + "trac_to_neuro_emission_multiplier": int( + self.neuro_emission_multiplier + * ( + 10**12 + if incentive_type == ParanetIncentivizationType.NEUROWEB + else 10**18 + ) ), - "paranetOperatorRewardPercentage": int(self.operator_percentage * 100), - "paranetIncentivizationProposalVotersRewardPercentage": int( + "paranet_operator_reward_percentage": int( + self.operator_percentage * 100 + ), + "paranet_incentivization_proposal_voters_reward_percentage": int( self.voters_percentage * 100 ), } - def __init__(self, manager: DefaultRequestManager): + def __init__( + self, + manager: DefaultRequestManager, + input_service: InputService, + blockchain_service: BlockchainService, + ): self.manager = manager - self.incentives_pools_deployment_functions = { - ParanetIncentivizationType.NEUROWEB: self._deploy_neuro_incentives_pool, - } - - _register_paranet = Method(BlockchainRequest.register_paranet) + self.input_service = input_service + self.blockchain_service = blockchain_service + self.incentive_type = ( + ParanetIncentivizationType.NEUROWEB + if self.manager.blockchain_provider.blockchain_id + in ( + BlockchainIds.NEUROWEB_DEVNET, + BlockchainIds.NEUROWEB_TESTNET, + BlockchainIds.NEUROWEB_MAINNET, + BlockchainIds.HARDHAT_1, + BlockchainIds.HARDHAT_2, + ) + else ParanetIncentivizationType.NEUROWEB_ERC20 + ) def create( self, ual: UAL, - name: str, - description: str, - paranet_nodes_access_policy: ParanetNodesAccessPolicy, - paranet_miners_access_policy: ParanetMinersAccessPolicy, + options: dict = {}, ) -> dict[str, str | HexStr | TxReceipt]: - parsed_ual = parse_ual(ual) - knowledge_asset_storage, knowledge_asset_token_id = ( - parsed_ual["contract_address"], - parsed_ual["token_id"], - ) + arguments = self.input_service.get_paranet_create_arguments(options) + name = arguments["paranet_name"] + description = arguments["paranet_description"] + paranet_nodes_access_policy = arguments["paranet_nodes_access_policy"] + paranet_miners_access_policy = arguments["paranet_miners_access_policy"] + + ( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + ) = get_paranet_ual_details(ual) - receipt: TxReceipt = self._register_paranet( - knowledge_asset_storage, - knowledge_asset_token_id, + receipt: TxReceipt = self.blockchain_service.register_paranet( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, name, description, paranet_nodes_access_policy, @@ -86,692 +113,602 @@ def create( return { "paranetUAL": ual, - "paranetId": Web3.to_hex( - Web3.solidity_keccak( - ["address", "uint256"], - [knowledge_asset_storage, knowledge_asset_token_id], - ) - ), - "operation": json.loads(Web3.to_json(receipt)), - } - - _add_paranet_curated_nodes = Method(BlockchainRequest.add_paranet_curated_nodes) - - def add_curated_nodes( - self, paranet_ual: UAL, identity_ids: list[int] - ) -> dict[str, str | HexStr | TxReceipt]: - parsed_ual = parse_ual(paranet_ual) - paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id = ( - parsed_ual["contract_address"], - parsed_ual["token_id"], - ) - - receipt = self._add_paranet_curated_nodes( - paranet_knowledge_asset_storage, - paranet_knowledge_asset_token_id, - identity_ids, - ) - - return { - "paranetUAL": paranet_ual, - "paranetId": Web3.to_hex( - Web3.solidity_keccak( - ["address", "uint256"], - [paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id], - ) - ), - "operation": json.loads(Web3.to_json(receipt)), - } - - _remove_paranet_curated_nodes = Method( - BlockchainRequest.remove_paranet_curated_nodes - ) - - def remove_curated_nodes( - self, paranet_ual: UAL, identity_ids: list[int] - ) -> dict[str, str | HexStr | TxReceipt]: - parsed_ual = parse_ual(paranet_ual) - paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id = ( - parsed_ual["contract_address"], - parsed_ual["token_id"], - ) - - receipt = self._remove_paranet_curated_nodes( - paranet_knowledge_asset_storage, - paranet_knowledge_asset_token_id, - identity_ids, - ) - - return { - "paranetUAL": paranet_ual, - "paranetId": Web3.to_hex( - Web3.solidity_keccak( - ["address", "uint256"], - [paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id], - ) - ), - "operation": json.loads(Web3.to_json(receipt)), - } - - _request_paranet_curated_node_access = Method( - BlockchainRequest.request_paranet_curated_node_access - ) - - def request_curated_node_access( - self, paranet_ual: UAL - ) -> dict[str, str | HexStr | TxReceipt]: - parsed_ual = parse_ual(paranet_ual) - paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id = ( - parsed_ual["contract_address"], - parsed_ual["token_id"], - ) - - receipt = self._request_paranet_curated_node_access( - paranet_knowledge_asset_storage, - paranet_knowledge_asset_token_id, - ) - - return { - "paranetUAL": paranet_ual, - "paranetId": Web3.to_hex( - Web3.solidity_keccak( - ["address", "uint256"], - [paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id], - ) - ), - "operation": json.loads(Web3.to_json(receipt)), - } - - _approve_curated_node = Method(BlockchainRequest.approve_curated_node) - - def approve_curated_node( - self, paranet_ual: UAL, identity_id: int - ) -> dict[str, str | HexStr | TxReceipt]: - parsed_ual = parse_ual(paranet_ual) - paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id = ( - parsed_ual["contract_address"], - parsed_ual["token_id"], - ) - - receipt = self._approve_curated_node( - paranet_knowledge_asset_storage, - paranet_knowledge_asset_token_id, - identity_id, - ) - - return { - "paranetUAL": paranet_ual, - "paranetId": Web3.to_hex( - Web3.solidity_keccak( - ["address", "uint256"], - [paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id], - ) - ), - "operation": json.loads(Web3.to_json(receipt)), - } - - _reject_curated_node = Method(BlockchainRequest.reject_curated_node) - - def reject_curated_node( - self, paranet_ual: UAL, identity_id: int - ) -> dict[str, str | HexStr | TxReceipt]: - parsed_ual = parse_ual(paranet_ual) - paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id = ( - parsed_ual["contract_address"], - parsed_ual["token_id"], - ) - - receipt = self._reject_curated_node( - paranet_knowledge_asset_storage, - paranet_knowledge_asset_token_id, - identity_id, - ) - - return { - "paranetUAL": paranet_ual, - "paranetId": Web3.to_hex( - Web3.solidity_keccak( - ["address", "uint256"], - [paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id], - ) - ), + "paranetId": Web3.to_hex(get_paranet_id(ual)), "operation": json.loads(Web3.to_json(receipt)), } - _get_curated_nodes = Method(BlockchainRequest.get_curated_nodes) - - def get_curated_nodes( - self, paranet_ual: UAL - ) -> dict[str, str | HexStr | TxReceipt]: - parsed_ual = parse_ual(paranet_ual) - paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id = ( - parsed_ual["contract_address"], - parsed_ual["token_id"], - ) - - paranet_id = Web3.solidity_keccak( - ["address", "uint256"], - [paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id], - ) - - return self._get_curated_nodes(paranet_id) - - _add_paranet_curated_miners = Method(BlockchainRequest.add_paranet_curated_miners) - - def add_curated_miners( - self, paranet_ual: UAL, miner_addresses: list[Address] - ) -> dict[str, str | HexStr | TxReceipt]: - parsed_ual = parse_ual(paranet_ual) - paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id = ( - parsed_ual["contract_address"], - parsed_ual["token_id"], - ) - - receipt = self._add_paranet_curated_miners( - paranet_knowledge_asset_storage, - paranet_knowledge_asset_token_id, - miner_addresses, - ) - - return { - "paranetUAL": paranet_ual, - "paranetId": Web3.to_hex( - Web3.solidity_keccak( - ["address", "uint256"], - [paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id], - ) - ), - "operation": json.loads(Web3.to_json(receipt)), - } - - _remove_paranet_curated_miners = Method( - BlockchainRequest.remove_paranet_curated_miners - ) - - def remove_curated_miners( - self, paranet_ual: UAL, miner_addresses: list[Address] - ) -> dict[str, str | HexStr | TxReceipt]: - parsed_ual = parse_ual(paranet_ual) - paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id = ( - parsed_ual["contract_address"], - parsed_ual["token_id"], - ) - - receipt = self._remove_paranet_curated_miners( - paranet_knowledge_asset_storage, - paranet_knowledge_asset_token_id, - miner_addresses, - ) - - return { - "paranetUAL": paranet_ual, - "paranetId": Web3.to_hex( - Web3.solidity_keccak( - ["address", "uint256"], - [paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id], - ) - ), - "operation": json.loads(Web3.to_json(receipt)), - } - - _request_paranet_curated_miner_access = Method( - BlockchainRequest.request_paranet_curated_miner_access - ) - - def request_curated_miner_access( - self, paranet_ual: UAL - ) -> dict[str, str | HexStr | TxReceipt]: - parsed_ual = parse_ual(paranet_ual) - paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id = ( - parsed_ual["contract_address"], - parsed_ual["token_id"], - ) - - receipt = self._request_paranet_curated_miner_access( - paranet_knowledge_asset_storage, - paranet_knowledge_asset_token_id, - ) - - return { - "paranetUAL": paranet_ual, - "paranetId": Web3.to_hex( - Web3.solidity_keccak( - ["address", "uint256"], - [paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id], - ) - ), - "operation": json.loads(Web3.to_json(receipt)), - } - - _approve_curated_miner = Method(BlockchainRequest.approve_curated_miner) - - def approve_curated_miner( - self, paranet_ual: UAL, miner_address: Address - ) -> dict[str, str | HexStr | TxReceipt]: - parsed_ual = parse_ual(paranet_ual) - paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id = ( - parsed_ual["contract_address"], - parsed_ual["token_id"], - ) - - receipt = self._approve_curated_miner( - paranet_knowledge_asset_storage, - paranet_knowledge_asset_token_id, - miner_address, - ) - - return { - "paranetUAL": paranet_ual, - "paranetId": Web3.to_hex( - Web3.solidity_keccak( - ["address", "uint256"], - [paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id], - ) - ), - "operation": json.loads(Web3.to_json(receipt)), - } - - _reject_curated_miner = Method(BlockchainRequest.reject_curated_miner) - - def reject_curated_miner( - self, paranet_ual: UAL, miner_address: Address - ) -> dict[str, str | HexStr | TxReceipt]: - parsed_ual = parse_ual(paranet_ual) - paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id = ( - parsed_ual["contract_address"], - parsed_ual["token_id"], - ) - - receipt = self._reject_curated_miner( - paranet_knowledge_asset_storage, - paranet_knowledge_asset_token_id, - miner_address, - ) - - return { - "paranetUAL": paranet_ual, - "paranetId": Web3.to_hex( - Web3.solidity_keccak( - ["address", "uint256"], - [paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id], - ) - ), - "operation": json.loads(Web3.to_json(receipt)), - } + # _add_paranet_curated_nodes = Method(BlockchainRequest.add_paranet_curated_nodes) + + # def add_curated_nodes( + # self, paranet_ual: UAL, identity_ids: list[int] + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._add_paranet_curated_nodes( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # identity_ids, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _remove_paranet_curated_nodes = Method( + # BlockchainRequest.remove_paranet_curated_nodes + # ) + + # def remove_curated_nodes( + # self, paranet_ual: UAL, identity_ids: list[int] + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._remove_paranet_curated_nodes( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # identity_ids, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _request_paranet_curated_node_access = Method( + # BlockchainRequest.request_paranet_curated_node_access + # ) + + # def request_curated_node_access( + # self, paranet_ual: UAL + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._request_paranet_curated_node_access( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _approve_curated_node = Method(BlockchainRequest.approve_curated_node) + + # def approve_curated_node( + # self, paranet_ual: UAL, identity_id: int + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._approve_curated_node( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # identity_id, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _reject_curated_node = Method(BlockchainRequest.reject_curated_node) + + # def reject_curated_node( + # self, paranet_ual: UAL, identity_id: int + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._reject_curated_node( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # identity_id, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _get_curated_nodes = Method(BlockchainRequest.get_curated_nodes) + + # def get_curated_nodes( + # self, paranet_ual: UAL + # ) -> dict[str, str | HexStr | TxReceipt]: + # paranet_id = get_paranet_id(paranet_ual) + + # return self._get_curated_nodes(paranet_id) + + # _add_paranet_curated_miners = Method(BlockchainRequest.add_paranet_curated_miners) + + # def add_curated_miners( + # self, paranet_ual: UAL, miner_addresses: list[Address] + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._add_paranet_curated_miners( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # miner_addresses, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _remove_paranet_curated_miners = Method( + # BlockchainRequest.remove_paranet_curated_miners + # ) + + # def remove_curated_miners( + # self, paranet_ual: UAL, miner_addresses: list[Address] + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._remove_paranet_curated_miners( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # miner_addresses, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _request_paranet_curated_miner_access = Method( + # BlockchainRequest.request_paranet_curated_miner_access + # ) + + # def request_curated_miner_access( + # self, paranet_ual: UAL + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._request_paranet_curated_miner_access( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _approve_curated_miner = Method(BlockchainRequest.approve_curated_miner) + + # def approve_curated_miner( + # self, paranet_ual: UAL, miner_address: Address + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._approve_curated_miner( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # miner_address, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _reject_curated_miner = Method(BlockchainRequest.reject_curated_miner) + + # def reject_curated_miner( + # self, paranet_ual: UAL, miner_address: Address + # ) -> dict[str, str | HexStr | TxReceipt]: + # ( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # ) = get_paranet_ual_details(paranet_ual) + + # receipt = self._reject_curated_miner( + # paranet_knowledge_collection_storage, + # paranet_knowledge_collection_token_id, + # paranet_knowledge_asset_token_id, + # miner_address, + # ) + + # return { + # "paranetUAL": paranet_ual, + # "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + # "operation": json.loads(Web3.to_json(receipt)), + # } _get_knowledge_miners = Method(BlockchainRequest.get_knowledge_miners) def get_knowledge_miners( self, paranet_ual: UAL ) -> dict[str, str | HexStr | TxReceipt]: - parsed_ual = parse_ual(paranet_ual) - paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id = ( - parsed_ual["contract_address"], - parsed_ual["token_id"], - ) - - paranet_id = Web3.solidity_keccak( - ["address", "uint256"], - [paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id], - ) + paranet_id = get_paranet_id(paranet_ual) return self._get_knowledge_miners(paranet_id) - _deploy_neuro_incentives_pool = Method( - BlockchainRequest.deploy_neuro_incentives_pool - ) - def deploy_incentives_contract( self, - ual: UAL, + paranet_ual: UAL, incentives_pool_parameters: NeuroWebIncentivesPoolParams, - incentives_type: ParanetIncentivizationType = ParanetIncentivizationType.NEUROWEB, ) -> dict[str, str | HexStr | TxReceipt]: - deploy_incentives_pool_fn = self.incentives_pools_deployment_functions.get( - incentives_type, - None, - ) + incentive_types = [item.value for item in ParanetIncentivizationType] + if self.incentive_type in incentive_types: + ( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + ) = get_paranet_ual_details(paranet_ual) + + is_native_reward = ( + True + if self.incentive_type == ParanetIncentivizationType.NEUROWEB + else False + ) - if deploy_incentives_pool_fn is None: - raise ValueError( - f"{incentives_type} Incentive Type isn't supported. Supported " - f"Incentive Types: {self.incentives_pools_deployment_functions.keys()}" + receipt: TxReceipt = self.blockchain_service.deploy_neuro_incentives_pool( + is_native_reward=is_native_reward, + paranet_knowledge_collection_storage=paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id=paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id=paranet_knowledge_asset_token_id, + **incentives_pool_parameters.to_contract_args(self.incentive_type), ) - parsed_ual = parse_ual(ual) - knowledge_asset_storage, knowledge_asset_token_id = ( - parsed_ual["contract_address"], - parsed_ual["token_id"], - ) + events = self.manager.blockchain_provider.decode_logs_event( + receipt, + "ParanetIncentivesPoolFactory", + "ParanetIncetivesPoolDeployed", + ) - receipt: TxReceipt = deploy_incentives_pool_fn( - knowledge_asset_storage, - knowledge_asset_token_id, - **incentives_pool_parameters.to_contract_args(), - ) + return { + "paranetUAL": paranet_ual, + "paranetId": Web3.to_hex(get_paranet_id(paranet_ual)), + "incentivesPoolContractAddress": events[0].args["incentivesPool"][ + "addr" + ], + "operation": json.loads(Web3.to_json(receipt)), + } - events = self.manager.blockchain_provider.decode_logs_event( - receipt, - "ParanetIncentivesPoolFactory", - "ParanetIncetivesPoolDeployed", + raise ValueError( + f"{self.incentive_type} Incentive Type isn't supported. Supported " + f"Incentive Types: {incentive_types}" ) - return { - "paranetUAL": ual, - "paranetId": Web3.to_hex( - Web3.solidity_keccak( - ["address", "uint256"], - [knowledge_asset_storage, knowledge_asset_token_id], - ) - ), - "incentivesPoolAddress": events[0].args["incentivesPool"]["addr"], - "operation": json.loads(Web3.to_json(receipt)), - } - - _get_incentives_pool_address = Method(BlockchainRequest.get_incentives_pool_address) - def get_incentives_pool_address( self, - ual: UAL, - incentives_type: ParanetIncentivizationType = ParanetIncentivizationType.NEUROWEB, + paranet_ual: UAL, ) -> Address: - parsed_ual = parse_ual(ual) - knowledge_asset_storage, knowledge_asset_token_id = ( - parsed_ual["contract_address"], - parsed_ual["token_id"], - ) - paranet_id = Web3.solidity_keccak( - ["address", "uint256"], [knowledge_asset_storage, knowledge_asset_token_id] - ) - - return self._get_incentives_pool_address(paranet_id, incentives_type) + paranet_id = get_paranet_id(paranet_ual) - _register_paranet_service = Method(BlockchainRequest.register_paranet_service) + return self.blockchain_service.get_incentives_pool_address( + paranet_id, self.incentive_type + ) def create_service( - self, ual: UAL, name: str, description: str, addresses: list[Address] + self, ual: UAL, options: dict = {} ) -> dict[str, str | HexStr | TxReceipt]: + arguments = self.input_service.get_paranet_create_service_arguments(options) + paranet_service_name = arguments["paranet_service_name"] + paranet_service_description = arguments["paranet_service_description"] + paranet_service_addresses = arguments["paranet_service_addresses"] + parsed_ual = parse_ual(ual) - knowledge_asset_storage, knowledge_asset_token_id = ( + knowledge_collection_storage, knowledge_collection_token_id = ( parsed_ual["contract_address"], - parsed_ual["token_id"], + parsed_ual["knowledge_collection_token_id"], ) + knowledge_asset_token_id = parsed_ual.get("knowledge_asset_token_id", None) - receipt: TxReceipt = self._register_paranet_service( - knowledge_asset_storage, + if not knowledge_asset_token_id: + raise ValidationError( + "Invalid paranet service UAL! Knowledge asset token id is required!" + ) + + receipt: TxReceipt = self.blockchain_service.register_paranet_service( + knowledge_collection_storage, + knowledge_collection_token_id, knowledge_asset_token_id, - name, - description, - addresses, + paranet_service_name, + paranet_service_description, + paranet_service_addresses, ) return { "paranetServiceUAL": ual, "paranetServiceId": Web3.to_hex( Web3.solidity_keccak( - ["address", "uint256"], - [knowledge_asset_storage, knowledge_asset_token_id], + ["address", "uint256", "uint256"], + [ + knowledge_collection_storage, + knowledge_collection_token_id, + knowledge_asset_token_id, + ], ) ), "operation": json.loads(Web3.to_json(receipt)), } - _add_paranet_services = Method(BlockchainRequest.add_paranet_services) - def add_services( self, ual: UAL, services_uals: list[UAL] ) -> dict[str, str | HexStr | TxReceipt]: - parsed_paranet_ual = parse_ual(ual) - paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id = ( - parsed_paranet_ual["contract_address"], - parsed_paranet_ual["token_id"], - ) + ( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + ) = get_paranet_ual_details(ual) parsed_service_uals = [] for service_ual in services_uals: parsed_service_ual = parse_ual(service_ual) - (service_knowledge_asset_storage, service_knowledge_asset_token_id) = ( + ( + service_knowledge_collection_storage, + service_knowledge_collection_token_id, + service_knowledge_asset_token_id, + ) = ( parsed_service_ual["contract_address"], - parsed_service_ual["token_id"], + parsed_service_ual["knowledge_collection_token_id"], + parsed_service_ual.get("knowledge_asset_token_id", None), ) + if not service_knowledge_asset_token_id: + raise ValidationError( + "Invalid paranet service UAL! Knowledge asset token id is required!" + ) + parsed_service_uals.append( - { - "knowledgeAssetStorageContract": service_knowledge_asset_storage, - "tokenId": service_knowledge_asset_token_id, - } + [ + service_knowledge_collection_storage, + service_knowledge_collection_token_id, + service_knowledge_asset_token_id, + ] ) - receipt: TxReceipt = self._add_paranet_services( - paranet_knowledge_asset_storage, + receipt: TxReceipt = self.blockchain_service.add_paranet_services( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, paranet_knowledge_asset_token_id, parsed_service_uals, ) return { "paranetUAL": ual, - "paranetId": Web3.to_hex( - Web3.solidity_keccak( - ["address", "uint256"], - [paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id], - ) - ), + "paranetId": Web3.to_hex(get_paranet_id(ual)), "operation": json.loads(Web3.to_json(receipt)), } - _is_knowledge_miner_registered = Method( - BlockchainRequest.is_knowledge_miner_registered - ) - - def is_knowledge_miner(self, ual: UAL, address: Address | None = None) -> bool: - parsed_ual = parse_ual(ual) - knowledge_asset_storage, knowledge_asset_token_id = ( - parsed_ual["contract_address"], - parsed_ual["token_id"], - ) - - paranet_id = Web3.solidity_keccak( - ["address", "uint256"], [knowledge_asset_storage, knowledge_asset_token_id] - ) - - return self._is_knowledge_miner_registered( - paranet_id, address or self.manager.blockchain_provider.account.address - ) - - _owner_of = Method(BlockchainRequest.owner_of) - - def is_operator(self, ual: UAL, address: Address | None = None) -> bool: - knowledge_asset_token_id = parse_ual(ual)["token_id"] - - return self._owner_of(knowledge_asset_token_id) == ( - address or self.manager.blockchain_provider.account.address - ) - - _is_proposal_voter = Method(BlockchainRequest.is_proposal_voter) - - def is_voter( + def is_knowledge_miner( self, - ual: UAL, + paranet_ual: UAL, address: Address | None = None, - incentives_type: ParanetIncentivizationType = ParanetIncentivizationType.NEUROWEB, ) -> bool: - return self._is_proposal_voter( - contract=self._get_incentives_pool_contract(ual, incentives_type), - addr=address or self.manager.blockchain_provider.account.address, - ) - - _get_claimable_knowledge_miner_reward_amount = Method( - BlockchainRequest.get_claimable_knowledge_miner_reward_amount - ) - - def calculate_claimable_miner_reward_amount( - self, - ual: UAL, - incentives_type: ParanetIncentivizationType = ParanetIncentivizationType.NEUROWEB, - ) -> int: - return self._get_claimable_knowledge_miner_reward_amount( - contract=self._get_incentives_pool_contract(ual, incentives_type) - ) + paranet_id = get_paranet_id(paranet_ual) - _get_claimable_all_knowledge_miners_reward_amount = Method( - BlockchainRequest.get_claimable_all_knowledge_miners_reward_amount - ) - - def calculate_all_claimable_miner_rewards_amount( - self, - ual: UAL, - incentives_type: ParanetIncentivizationType = ParanetIncentivizationType.NEUROWEB, - ) -> int: - return self._get_claimable_all_knowledge_miners_reward_amount( - contract=self._get_incentives_pool_contract(ual, incentives_type) - ) - - _claim_knowledge_miner_reward = Method( - BlockchainRequest.claim_knowledge_miner_reward - ) - - def claim_miner_reward( - self, - ual: UAL, - incentives_type: ParanetIncentivizationType = ParanetIncentivizationType.NEUROWEB, - ) -> dict[str, str | HexStr | TxReceipt]: - receipt: TxReceipt = self._claim_knowledge_miner_reward( - contract=self._get_incentives_pool_contract(ual, incentives_type) - ) - - parsed_ual = parse_ual(ual) - knowledge_asset_storage, knowledge_asset_token_id = ( - parsed_ual["contract_address"], - parsed_ual["token_id"], - ) - - return { - "paranetUAL": ual, - "paranetId": Web3.to_hex( - Web3.solidity_keccak( - ["address", "uint256"], - [knowledge_asset_storage, knowledge_asset_token_id], - ) - ), - "operation": json.loads(Web3.to_json(receipt)), - } - - _get_claimable_paranet_operator_reward_amount = Method( - BlockchainRequest.get_claimable_paranet_operator_reward_amount - ) - - def calculate_claimable_operator_reward_amount( - self, - ual: UAL, - incentives_type: ParanetIncentivizationType = ParanetIncentivizationType.NEUROWEB, - ) -> int: - return self._get_claimable_paranet_operator_reward_amount( - contract=self._get_incentives_pool_contract(ual, incentives_type) - ) - - _claim_paranet_operator_reward = Method( - BlockchainRequest.claim_paranet_operator_reward - ) - - def claim_operator_reward( - self, - ual: UAL, - incentives_type: ParanetIncentivizationType = ParanetIncentivizationType.NEUROWEB, - ) -> dict[str, str | HexStr | TxReceipt]: - receipt: TxReceipt = self._claim_paranet_operator_reward( - contract=self._get_incentives_pool_contract(ual, incentives_type) - ) - - parsed_ual = parse_ual(ual) - knowledge_asset_storage, knowledge_asset_token_id = ( - parsed_ual["contract_address"], - parsed_ual["token_id"], - ) - - return { - "paranetUAL": ual, - "paranetId": Web3.to_hex( - Web3.solidity_keccak( - ["address", "uint256"], - [knowledge_asset_storage, knowledge_asset_token_id], - ) - ), - "operation": json.loads(Web3.to_json(receipt)), - } - - _get_claimable_proposal_voter_reward_amount = Method( - BlockchainRequest.get_claimable_proposal_voter_reward_amount - ) - - def calculate_claimable_voter_reward_amount( - self, - ual: UAL, - incentives_type: ParanetIncentivizationType = ParanetIncentivizationType.NEUROWEB, - ) -> int: - return self._get_claimable_proposal_voter_reward_amount( - contract=self._get_incentives_pool_contract(ual, incentives_type) + return self.blockchain_service.is_knowledge_miner_registered( + paranet_id, address or self.manager.blockchain_provider.account.address ) - _get_claimable_all_proposal_voters_reward_amount = Method( - BlockchainRequest.get_claimable_all_proposal_voters_reward_amount - ) - - def calculate_all_claimable_voters_reward_amount( + def is_operator( self, - ual: UAL, - incentives_type: ParanetIncentivizationType = ParanetIncentivizationType.NEUROWEB, - ) -> int: - return self._get_claimable_all_proposal_voters_reward_amount( - contract=self._get_incentives_pool_contract(ual, incentives_type) - ) - - _claim_incentivization_proposal_voter_reward = Method( - BlockchainRequest.claim_incentivization_proposal_voter_reward - ) + paranet_ual: UAL, + address: Address | None = None, + ) -> bool: + incentives_pool_address = self.get_incentives_pool_address(paranet_ual) - def claim_voter_reward( - self, - ual: UAL, - incentives_type: ParanetIncentivizationType = ParanetIncentivizationType.NEUROWEB, - ) -> dict[str, str | HexStr | TxReceipt]: - receipt: TxReceipt = self._claim_incentivization_proposal_voter_reward( - contract=self._get_incentives_pool_contract(ual, incentives_type) - ) + self.blockchain_service.set_incentives_pool(incentives_pool_address) - parsed_ual = parse_ual(ual) - knowledge_asset_storage, knowledge_asset_token_id = ( - parsed_ual["contract_address"], - parsed_ual["token_id"], + return self.blockchain_service.is_paranet_operator( + operator_address=address or self.manager.blockchain_provider.account.address ) - return { - "paranetUAL": ual, - "paranetId": Web3.to_hex( - Web3.solidity_keccak( - ["address", "uint256"], - [knowledge_asset_storage, knowledge_asset_token_id], - ) - ), - "operation": json.loads(Web3.to_json(receipt)), - } - - - - def _get_incentives_pool_contract( + def is_voter( self, - ual: UAL, - incentives_type: ParanetIncentivizationType = ParanetIncentivizationType.NEUROWEB, - ) -> str | dict[str, str]: - incentives_pool_name = f"Paranet{str(incentives_type)}IncentivesPool" - is_incentives_pool_cached = ( - incentives_pool_name in self.manager.blockchain_provider.contracts.keys() - ) - - return ( - incentives_pool_name - if is_incentives_pool_cached - else { - "name": incentives_pool_name, - "address": self.get_incentives_pool_address(ual, incentives_type), - } - ) + paranet_ual: UAL, + address: Address | None = None, + ) -> bool: + incentives_pool_address = self.get_incentives_pool_address(paranet_ual) + + self.blockchain_service.set_incentives_pool(incentives_pool_address) + + return self.blockchain_service.is_proposal_voter( + address=address or self.manager.blockchain_provider.account.address, + ) + + # _get_claimable_knowledge_miner_reward_amount = Method( + # BlockchainRequest.get_claimable_knowledge_miner_reward_amount + # ) + + # def calculate_claimable_miner_reward_amount( + # self, + # ual: UAL, + # + # ) -> int: + # return self._get_claimable_knowledge_miner_reward_amount( + # contract=self._get_incentives_pool_contract(ual) + # ) + + # _get_claimable_all_knowledge_miners_reward_amount = Method( + # BlockchainRequest.get_claimable_all_knowledge_miners_reward_amount + # ) + + # def calculate_all_claimable_miner_rewards_amount( + # self, + # ual: UAL, + # + # ) -> int: + # return self._get_claimable_all_knowledge_miners_reward_amount( + # contract=self._get_incentives_pool_contract(ual) + # ) + + # _claim_knowledge_miner_reward = Method( + # BlockchainRequest.claim_knowledge_miner_reward + # ) + + # def claim_miner_reward( + # self, + # ual: UAL, + # + # ) -> dict[str, str | HexStr | TxReceipt]: + # receipt: TxReceipt = self._claim_knowledge_miner_reward( + # contract=self._get_incentives_pool_contract(ual) + # ) + + # paranet_id = get_paranet_id(ual) + + # return { + # "paranetUAL": ual, + # "paranetId": Web3.to_hex(paranet_id), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _get_claimable_paranet_operator_reward_amount = Method( + # BlockchainRequest.get_claimable_paranet_operator_reward_amount + # ) + + # def calculate_claimable_operator_reward_amount( + # self, + # ual: UAL, + # + # ) -> int: + # return self._get_claimable_paranet_operator_reward_amount( + # contract=self._get_incentives_pool_contract(ual) + # ) + + # _claim_paranet_operator_reward = Method( + # BlockchainRequest.claim_paranet_operator_reward + # ) + + # def claim_operator_reward( + # self, + # ual: UAL, + # + # ) -> dict[str, str | HexStr | TxReceipt]: + # receipt: TxReceipt = self._claim_paranet_operator_reward( + # contract=self._get_incentives_pool_contract(ual) + # ) + + # paranet_id = get_paranet_id(ual) + + # return { + # "paranetUAL": ual, + # "paranetId": Web3.to_hex(paranet_id), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # _get_claimable_proposal_voter_reward_amount = Method( + # BlockchainRequest.get_claimable_proposal_voter_reward_amount + # ) + + # def calculate_claimable_voter_reward_amount( + # self, + # ual: UAL, + # + # ) -> int: + # return self._get_claimable_proposal_voter_reward_amount( + # contract=self._get_incentives_pool_contract(ual) + # ) + + # _get_claimable_all_proposal_voters_reward_amount = Method( + # BlockchainRequest.get_claimable_all_proposal_voters_reward_amount + # ) + + # def calculate_all_claimable_voters_reward_amount( + # self, + # ual: UAL, + # + # ) -> int: + # return self._get_claimable_all_proposal_voters_reward_amount( + # contract=self._get_incentives_pool_contract(ual) + # ) + + # _claim_incentivization_proposal_voter_reward = Method( + # BlockchainRequest.claim_incentivization_proposal_voter_reward + # ) + + # def claim_voter_reward( + # self, + # ual: UAL, + # + # ) -> dict[str, str | HexStr | TxReceipt]: + # receipt: TxReceipt = self._claim_incentivization_proposal_voter_reward( + # contract=self._get_incentives_pool_contract(ual) + # ) + + # paranet_id = get_paranet_id(ual) + + # return { + # "paranetUAL": ual, + # "paranetId": Web3.to_hex(paranet_id), + # "operation": json.loads(Web3.to_json(receipt)), + # } + + # def _get_incentives_pool_contract( + # self, + # ual: UAL, + # ) -> str | dict[str, str]: + # incentives_pool_name = f"Paranet{str(self.incentive_type)}IncentivesPool" + # is_incentives_pool_cached = ( + # incentives_pool_name in self.manager.blockchain_provider.contracts.keys() + # ) + + # return ( + # incentives_pool_name + # if is_incentives_pool_cached + # else { + # "name": incentives_pool_name, + # "address": self.get_incentives_pool_address(ual), + # } + # ) diff --git a/dkg/providers/blockchain/async_blockchain.py b/dkg/providers/blockchain/async_blockchain.py index 6f3f382..bbd4029 100644 --- a/dkg/providers/blockchain/async_blockchain.py +++ b/dkg/providers/blockchain/async_blockchain.py @@ -243,3 +243,17 @@ async def _check_contract_status(self, contract: str) -> bool: return await self.call_function(contract, "status") except Exception: return False + + def set_incentives_pool(self, incentives_pool_address: Address): + # Update contract address if different + if ( + self.contracts.get("ParanetNeuroIncentivesPool") is None + or self.contracts["ParanetNeuroIncentivesPool"].address + != incentives_pool_address + ): + # Create new contract instance + self.contracts["ParanetNeuroIncentivesPool"] = self.w3.eth.contract( + address=incentives_pool_address, + abi=self.abi["ParanetNeuroIncentivesPool"], + decode_tuples=True, + ) diff --git a/dkg/providers/blockchain/base_blockchain.py b/dkg/providers/blockchain/base_blockchain.py index 5ff52d2..7ebe62b 100644 --- a/dkg/providers/blockchain/base_blockchain.py +++ b/dkg/providers/blockchain/base_blockchain.py @@ -100,3 +100,6 @@ def set_account(self, private_key: DataHexStr): layer=0, ) self.w3.eth.default_account = self.account.address + + def set_incentives_pool(self): + raise NotImplementedError("This method has to be implemented in the subclass") diff --git a/dkg/providers/blockchain/blockchain.py b/dkg/providers/blockchain/blockchain.py index 1c2f6a4..75c5e2e 100644 --- a/dkg/providers/blockchain/blockchain.py +++ b/dkg/providers/blockchain/blockchain.py @@ -226,3 +226,17 @@ def _check_contract_status(self, contract: str) -> bool: return self.call_function(contract, "status") except Exception: return False + + def set_incentives_pool(self, incentives_pool_address: Address): + # Update contract address if different + if ( + self.contracts.get("ParanetNeuroIncentivesPool") is None + or self.contracts["ParanetNeuroIncentivesPool"].address + != incentives_pool_address + ): + # Create new contract instance + self.contracts["ParanetNeuroIncentivesPool"] = self.w3.eth.contract( + address=incentives_pool_address, + abi=self.abi["ParanetNeuroIncentivesPool"], + decode_tuples=True, + ) diff --git a/dkg/modules/network/__init__.py b/dkg/request_managers/__init__.py similarity index 100% rename from dkg/modules/network/__init__.py rename to dkg/request_managers/__init__.py diff --git a/dkg/utils/blockchain_request.py b/dkg/request_managers/blockchain_request.py similarity index 81% rename from dkg/utils/blockchain_request.py rename to dkg/request_managers/blockchain_request.py index 9b90641..731e436 100644 --- a/dkg/utils/blockchain_request.py +++ b/dkg/request_managers/blockchain_request.py @@ -119,37 +119,27 @@ class BlockchainRequest: args={"spender": Address, "subtractedValue": Wei}, ) - burn_asset = ContractTransaction( - contract="ContentAsset", - function="burnAsset", - args={"tokenId": int}, - ) - extend_asset_storing_period = ContractTransaction( - contract="ContentAsset", - function="extendAssetStoringPeriod", - args={"tokenId": int, "epochsNumber": int, "tokenAmount": int}, + burn_knowledge_assets_tokens = ContractTransaction( + contract="KnowledgeCollectionStorage", + function="burnKnowledgeAssetsTokens", + args={"id": int, "from": Address, "tokenIds": list[int]}, ) + # extend_asset_storing_period = ContractTransaction( + # contract="ContentAsset", + # function="extendAssetStoringPeriod", + # args={"tokenId": int, "epochsNumber": int, "tokenAmount": int}, + # ) transfer_asset = ContractTransaction( - contract="ContentAssetStorage", - function="transferFrom", - args={"from": Address, "to": Address, "tokenId": int}, - ) - get_latest_assertion_id = ContractCall( - contract="ContentAssetStorage", - function="getLatestAssertionId", - args={"tokenId": int}, - ) - owner_of = ContractCall( - contract="ContentAssetStorage", - function="ownerOf", - args={"tokenId": int}, + contract="KnowledgeCollectionStorage", + function="safeTransferFrom", + args={"from": Address, "to": Address, "id": int, "amount": int, "data": bytes}, ) - get_assertion_size = ContractCall( - contract="AssertionStorage", - function="getAssertionSize", - args={"assertionId": bytes | HexStr}, + is_knowledge_collection_owner = ContractCall( + contract="KnowledgeCollectionStorage", + function="isKnowledgeCollectionOwner", + args={"owner": Address, "id": int}, ) # Identity @@ -164,7 +154,8 @@ class BlockchainRequest: contract="Paranet", function="registerParanet", args={ - "paranetKAStorageContract": Address, + "paranetKCStorageContract": Address, + "paranetKCTokenId": int, "paranetKATokenId": int, "paranetName": str, "paranetDescription": str, @@ -173,11 +164,18 @@ class BlockchainRequest: }, ) + is_paranet_operator = ContractCall( + contract="ParanetNeuroIncentivesPool", + function="isParanetOperator", + args={"addr": Address}, + ) + add_paranet_curated_nodes = ContractTransaction( contract="Paranet", function="addParanetCuratedNodes", args={ - "paranetKAStorageContract": Address, + "paranetKCStorageContract": Address, + "paranetKCTokenId": int, "paranetKATokenId": int, "identityIds": list[int], }, @@ -187,7 +185,8 @@ class BlockchainRequest: contract="Paranet", function="removeParanetCuratedNodes", args={ - "paranetKAStorageContract": Address, + "paranetKCStorageContract": Address, + "paranetKCTokenId": int, "paranetKATokenId": int, "identityIds": list[int], }, @@ -197,7 +196,8 @@ class BlockchainRequest: contract="Paranet", function="requestParanetCuratedNodeAccess", args={ - "paranetKAStorageContract": Address, + "paranetKCStorageContract": Address, + "paranetKCTokenId": int, "paranetKATokenId": int, }, ) @@ -206,7 +206,8 @@ class BlockchainRequest: contract="Paranet", function="approveCuratedNode", args={ - "paranetKAStorageContract": Address, + "paranetKCStorageContract": Address, + "paranetKCTokenId": int, "paranetKATokenId": int, "identityId": int, }, @@ -216,7 +217,8 @@ class BlockchainRequest: contract="Paranet", function="rejectCuratedNode", args={ - "paranetKAStorageContract": Address, + "paranetKCStorageContract": Address, + "paranetKCTokenId": int, "paranetKATokenId": int, "identityId": int, }, @@ -232,7 +234,8 @@ class BlockchainRequest: contract="Paranet", function="addParanetCuratedMiners", args={ - "paranetKAStorageContract": Address, + "paranetKCStorageContract": Address, + "paranetKCTokenId": int, "paranetKATokenId": int, "minerAddresses": list[Address], }, @@ -242,7 +245,8 @@ class BlockchainRequest: contract="Paranet", function="removeParanetCuratedMiners", args={ - "paranetKAStorageContract": Address, + "paranetKCStorageContract": Address, + "paranetKCTokenId": int, "paranetKATokenId": int, "minerAddresses": list[Address], }, @@ -252,7 +256,8 @@ class BlockchainRequest: contract="Paranet", function="requestParanetCuratedMinerAccess", args={ - "paranetKAStorageContract": Address, + "paranetKCStorageContract": Address, + "paranetKCTokenId": int, "paranetKATokenId": int, }, ) @@ -261,7 +266,8 @@ class BlockchainRequest: contract="Paranet", function="approveCuratedMiner", args={ - "paranetKAStorageContract": Address, + "paranetKCStorageContract": Address, + "paranetKCTokenId": int, "paranetKATokenId": int, "minerAddress": Address, }, @@ -271,7 +277,8 @@ class BlockchainRequest: contract="Paranet", function="rejectCuratedMiner", args={ - "paranetKAStorageContract": Address, + "paranetKCStorageContract": Address, + "paranetKCTokenId": int, "paranetKATokenId": int, "minerAddress": Address, }, @@ -287,7 +294,8 @@ class BlockchainRequest: contract="Paranet", function="addParanetServices", args={ - "paranetKAStorageContract": Address, + "paranetKCStorageContract": Address, + "paranetKCTokenId": int, "paranetKATokenId": int, "services": dict[str, Address | int], }, @@ -296,7 +304,8 @@ class BlockchainRequest: contract="Paranet", function="registerParanetService", args={ - "paranetServiceKAStorageContract": Address, + "paranetServiceKCStorageContract": Address, + "paranetServiceKCTokenId": int, "paranetServiceKATokenId": int, "paranetServiceName": str, "paranetServiceDescription": str, @@ -308,7 +317,8 @@ class BlockchainRequest: function="submitKnowledgeCollection", args={ "paranetKCStorageContract": Address, - "paranetKnowledgeCollectionId": int, + "paranetKnowledgeCollectionTokenId": int, + "paranetKnowledgeAssetTokenId": int, "knowledgeCollectionStorageContract": Address, "knowledgeCollectionTokenId": int, }, @@ -318,7 +328,9 @@ class BlockchainRequest: contract="ParanetIncentivesPoolFactory", function="deployNeuroIncentivesPool", args={ - "paranetKAStorageContract": Address, + "isNativeReward": bool, + "paranetKCStorageContract": Address, + "paranetKCTokenId": int, "paranetKATokenId": int, "tracToNeuroEmissionMultiplier": float, "paranetOperatorRewardPercentage": float, @@ -334,15 +346,6 @@ class BlockchainRequest: }, ) - get_updating_knowledge_collection_states = ContractCall( - contract="ParanetKnowledgeMinersRegistry", - function="getUpdatingKnowledgeCollectionStates", - args={ - "miner": Address, - "paranetId": HexStr, - }, - ) - is_knowledge_miner_registered = ContractCall( contract="ParanetsRegistry", function="isKnowledgeMinerRegistered", @@ -352,6 +355,7 @@ class BlockchainRequest: }, ) is_proposal_voter = ContractCall( + contract="ParanetNeuroIncentivesPool", function="isProposalVoter", args={"addr": Address}, ) diff --git a/dkg/utils/node_request.py b/dkg/request_managers/node_request.py similarity index 90% rename from dkg/utils/node_request.py rename to dkg/request_managers/node_request.py index 28f7972..bcc3ef3 100644 --- a/dkg/utils/node_request.py +++ b/dkg/request_managers/node_request.py @@ -19,9 +19,9 @@ from enum import auto, Enum from typing import Any, Type, Dict -from dkg.dataclasses import BidSuggestionRange, HTTPRequestMethod +from dkg.dataclasses import HTTPRequestMethod from dkg.exceptions import OperationFailed, OperationNotFinished -from dkg.types import AutoStrEnumUpperCase, UAL, Address, DataHexStr +from dkg.types import AutoStrEnumUpperCase, UAL @dataclass @@ -34,19 +34,7 @@ class NodeCall: class NodeRequest: info = NodeCall(method=HTTPRequestMethod.GET, path="info") - bid_suggestion = NodeCall( - method=HTTPRequestMethod.GET, - path="bid-suggestion", - params={ - "blockchain": str, - "epochsNumber": int, - "assertionSize": int, - "contentAssetStorageAddress": Address, - "firstAssertionId": DataHexStr, - "hashFunctionId": int, - "bidSuggestionRange": BidSuggestionRange, - }, - ) + get_operation_result = NodeCall( method=HTTPRequestMethod.GET, path="{operation}/{operation_id}", @@ -99,7 +87,7 @@ class NodeRequest: "query": str, "type": str, "repository": str | None, - "paranet_ual": str | None, + "paranetUAL": str | None, }, ) diff --git a/dkg/services/blockchain_services/async_blockchain_service.py b/dkg/services/blockchain_services/async_blockchain_service.py index 649990e..7306464 100644 --- a/dkg/services/blockchain_services/async_blockchain_service.py +++ b/dkg/services/blockchain_services/async_blockchain_service.py @@ -1,35 +1,23 @@ from dkg.modules.async_module import AsyncModule from dkg.managers.async_manager import AsyncRequestManager -from dkg.utils.blockchain_request import BlockchainRequest -from dkg.method import Method from dkg.constants import ZERO_ADDRESS from web3 import Web3 from typing import Optional -from dkg.types import Address, UAL -from dkg.utils.blockchain_request import KnowledgeCollectionResult, AllowanceResult -from dkg.utils.ual import parse_ual +from dkg.types import Address, HexStr +from dkg.request_managers.blockchain_request import ( + KnowledgeCollectionResult, + AllowanceResult, +) +from dkg.dataclasses import ParanetIncentivizationType +from dkg.services.blockchain_services.base_blockchain_service import ( + BaseBlockchainService, +) -class AsyncBlockchainService(AsyncModule): +class AsyncBlockchainService(AsyncModule, BaseBlockchainService): def __init__(self, manager: AsyncRequestManager): self.manager = manager - _owner = Method(BlockchainRequest.owner_of) - _get_contract_address = Method(BlockchainRequest.get_contract_address) - _get_current_allowance = Method(BlockchainRequest.allowance) - _increase_allowance = Method(BlockchainRequest.increase_allowance) - _decrease_allowance = Method(BlockchainRequest.decrease_allowance) - _create_knowledge_collection = Method(BlockchainRequest.create_knowledge_collection) - _mint_knowledge_collection = Method(BlockchainRequest.mint_knowledge_collection) - _get_asset_storage_address = Method(BlockchainRequest.get_asset_storage_address) - _key_is_operational_wallet = Method(BlockchainRequest.key_is_operational_wallet) - _time_until_next_epoch = Method(BlockchainRequest.time_until_next_epoch) - _epoch_length = Method(BlockchainRequest.epoch_length) - _get_stake_weighted_average_ask = Method( - BlockchainRequest.get_stake_weighted_average_ask - ) - _get_block = Method(BlockchainRequest.get_block) - async def decrease_knowledge_collection_allowance( self, allowance_gap: int, @@ -153,12 +141,6 @@ async def create_knowledge_collection( await self.decrease_knowledge_collection_allowance(allowance_gap) raise e - # TODO: change self._owner to v8 compatible function - async def get_owner(self, ual: UAL) -> Address: - token_id = parse_ual(ual)["token_id"] - - return await self._owner(token_id) - async def get_asset_storage_address(self, asset_storage_name: str) -> Address: return await self._get_asset_storage_address(asset_storage_name) @@ -178,3 +160,121 @@ async def get_stake_weighted_average_ask(self) -> int: async def get_block(self, block_identifier: str | int): return await self._get_block(block_identifier) + + async def register_paranet( + self, + knowledge_collection_storage: str | Address, + knowledge_collection_token_id: int, + knowledge_asset_token_id: int, + name: str, + description: str, + paranet_nodes_access_policy: int, + paranet_miners_access_policy: int, + ): + return await self._register_paranet( + knowledge_collection_storage, + knowledge_collection_token_id, + knowledge_asset_token_id, + name, + description, + paranet_nodes_access_policy, + paranet_miners_access_policy, + ) + + async def submit_knowledge_collection( + self, + paranet_knowledge_collection_storage: str | Address, + paranet_knowledge_collection_token_id: int, + paranet_knowledge_asset_token_id: int, + knowledge_collection_storage: str | Address, + knowledge_collection_token_id: int, + ): + return await self._submit_knowledge_collection( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + knowledge_collection_storage, + knowledge_collection_token_id, + ) + + async def register_paranet_service( + self, + knowledge_collection_storage: str | Address, + knowledge_collection_token_id: int, + knowledge_asset_token_id: int, + paranet_service_name: str, + paranet_service_description: str, + paranet_service_addresses: list[Address], + ): + return await self._register_paranet_service( + knowledge_collection_storage, + knowledge_collection_token_id, + knowledge_asset_token_id, + paranet_service_name, + paranet_service_description, + paranet_service_addresses, + ) + + async def add_paranet_services( + self, + paranet_knowledge_collection_storage: str | Address, + paranet_knowledge_collection_token_id: int, + paranet_knowledge_asset_token_id: int, + services: list, + ): + return await self._add_paranet_services( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + services, + ) + + async def deploy_neuro_incentives_pool( + self, + is_native_reward: bool, + paranet_knowledge_collection_storage: str | Address, + paranet_knowledge_collection_token_id: int, + paranet_knowledge_asset_token_id: int, + trac_to_neuro_emission_multiplier: float, + paranet_operator_reward_percentage: float, + paranet_incentivization_proposal_voters_reward_percentage: float, + ): + return await self._deploy_neuro_incentives_pool( + is_native_reward, + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + trac_to_neuro_emission_multiplier, + paranet_operator_reward_percentage, + paranet_incentivization_proposal_voters_reward_percentage, + ) + + async def get_incentives_pool_address( + self, paranet_id: HexStr, incentives_pool_type: ParanetIncentivizationType + ): + return await self._get_incentives_pool_address(paranet_id, incentives_pool_type) + + async def is_knowledge_miner_registered(self, paranet_id: HexStr, address: Address): + return await self._is_knowledge_miner_registered(paranet_id, address) + + async def is_knowledge_collection_owner(self, owner: Address, id: int): + return await self._is_knowledge_collection_owner(owner, id) + + async def is_paranet_operator(self, operator_address: Address): + return await self._is_paranet_operator(operator_address) + + def set_incentives_pool(self, incentives_pool_address: Address): + self.manager.blockchain_provider.set_incentives_pool(incentives_pool_address) + + async def is_proposal_voter(self, address: Address): + return await self._is_proposal_voter(address) + + async def burn_knowledge_assets_tokens( + self, id: int, from_: Address, token_ids: list[int] + ): + return await self._burn_knowledge_assets_tokens(id, from_, token_ids) + + async def transfer_asset(self, from_: Address, to: Address, token_id: int): + return await self._transfer_asset( + from_, to, token_id, 1, Web3.to_bytes(hexstr="0x") + ) diff --git a/dkg/services/blockchain_services/base_blockchain_service.py b/dkg/services/blockchain_services/base_blockchain_service.py new file mode 100644 index 0000000..ac778b6 --- /dev/null +++ b/dkg/services/blockchain_services/base_blockchain_service.py @@ -0,0 +1,40 @@ +from dkg.method import Method +from dkg.request_managers.blockchain_request import BlockchainRequest + + +class BaseBlockchainService: + # Common methods shared between sync and async services + _get_contract_address = Method(BlockchainRequest.get_contract_address) + _get_current_allowance = Method(BlockchainRequest.allowance) + _increase_allowance = Method(BlockchainRequest.increase_allowance) + _decrease_allowance = Method(BlockchainRequest.decrease_allowance) + _create_knowledge_collection = Method(BlockchainRequest.create_knowledge_collection) + _mint_knowledge_collection = Method(BlockchainRequest.mint_knowledge_collection) + _get_asset_storage_address = Method(BlockchainRequest.get_asset_storage_address) + _key_is_operational_wallet = Method(BlockchainRequest.key_is_operational_wallet) + _time_until_next_epoch = Method(BlockchainRequest.time_until_next_epoch) + _epoch_length = Method(BlockchainRequest.epoch_length) + _get_stake_weighted_average_ask = Method( + BlockchainRequest.get_stake_weighted_average_ask + ) + _get_block = Method(BlockchainRequest.get_block) + _register_paranet = Method(BlockchainRequest.register_paranet) + _submit_knowledge_collection = Method(BlockchainRequest.submit_knowledge_collection) + _register_paranet_service = Method(BlockchainRequest.register_paranet_service) + _add_paranet_services = Method(BlockchainRequest.add_paranet_services) + _deploy_neuro_incentives_pool = Method( + BlockchainRequest.deploy_neuro_incentives_pool + ) + _get_incentives_pool_address = Method(BlockchainRequest.get_incentives_pool_address) + _is_knowledge_miner_registered = Method( + BlockchainRequest.is_knowledge_miner_registered + ) + _is_knowledge_collection_owner = Method( + BlockchainRequest.is_knowledge_collection_owner + ) + _is_paranet_operator = Method(BlockchainRequest.is_paranet_operator) + _is_proposal_voter = Method(BlockchainRequest.is_proposal_voter) + _burn_knowledge_assets_tokens = Method( + BlockchainRequest.burn_knowledge_assets_tokens + ) + _transfer_asset = Method(BlockchainRequest.transfer_asset) diff --git a/dkg/services/blockchain_services/blockchain_service.py b/dkg/services/blockchain_services/blockchain_service.py index eddea4d..ae2cd65 100644 --- a/dkg/services/blockchain_services/blockchain_service.py +++ b/dkg/services/blockchain_services/blockchain_service.py @@ -1,35 +1,23 @@ from dkg.modules.module import Module from dkg.managers.manager import DefaultRequestManager -from dkg.utils.blockchain_request import BlockchainRequest -from dkg.method import Method from dkg.constants import ZERO_ADDRESS from web3 import Web3 from typing import Optional -from dkg.types import Address, UAL -from dkg.utils.blockchain_request import KnowledgeCollectionResult, AllowanceResult -from dkg.utils.ual import parse_ual +from dkg.types import Address, HexStr +from dkg.request_managers.blockchain_request import ( + KnowledgeCollectionResult, + AllowanceResult, +) +from dkg.dataclasses import ParanetIncentivizationType +from dkg.services.blockchain_services.base_blockchain_service import ( + BaseBlockchainService, +) -class BlockchainService(Module): +class BlockchainService(Module, BaseBlockchainService): def __init__(self, manager: DefaultRequestManager): self.manager = manager - _owner = Method(BlockchainRequest.owner_of) - _get_contract_address = Method(BlockchainRequest.get_contract_address) - _get_current_allowance = Method(BlockchainRequest.allowance) - _increase_allowance = Method(BlockchainRequest.increase_allowance) - _decrease_allowance = Method(BlockchainRequest.decrease_allowance) - _create_knowledge_collection = Method(BlockchainRequest.create_knowledge_collection) - _mint_knowledge_collection = Method(BlockchainRequest.mint_knowledge_collection) - _get_asset_storage_address = Method(BlockchainRequest.get_asset_storage_address) - _key_is_operational_wallet = Method(BlockchainRequest.key_is_operational_wallet) - _time_until_next_epoch = Method(BlockchainRequest.time_until_next_epoch) - _epoch_length = Method(BlockchainRequest.epoch_length) - _get_stake_weighted_average_ask = Method( - BlockchainRequest.get_stake_weighted_average_ask - ) - _get_block = Method(BlockchainRequest.get_block) - def decrease_knowledge_collection_allowance( self, allowance_gap: int, @@ -147,12 +135,6 @@ def create_knowledge_collection( self.decrease_knowledge_collection_allowance(allowance_gap) raise e - # TODO: change self._owner to v8 compatible function - def get_owner(self, ual: UAL) -> Address: - token_id = parse_ual(ual)["token_id"] - - return self._owner(token_id) - def get_asset_storage_address(self, asset_storage_name: str) -> Address: return self._get_asset_storage_address(asset_storage_name) @@ -172,3 +154,119 @@ def get_stake_weighted_average_ask(self) -> int: def get_block(self, block_identifier: str | int): return self._get_block(block_identifier) + + def register_paranet( + self, + knowledge_collection_storage: str | Address, + knowledge_collection_token_id: int, + knowledge_asset_token_id: int, + name: str, + description: str, + paranet_nodes_access_policy: int, + paranet_miners_access_policy: int, + ): + return self._register_paranet( + knowledge_collection_storage, + knowledge_collection_token_id, + knowledge_asset_token_id, + name, + description, + paranet_nodes_access_policy, + paranet_miners_access_policy, + ) + + def submit_knowledge_collection( + self, + paranet_knowledge_collection_storage: str | Address, + paranet_knowledge_collection_token_id: int, + paranet_knowledge_asset_token_id: int, + knowledge_collection_storage: str | Address, + knowledge_collection_token_id: int, + ): + return self._submit_knowledge_collection( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + knowledge_collection_storage, + knowledge_collection_token_id, + ) + + def register_paranet_service( + self, + knowledge_collection_storage: str | Address, + knowledge_collection_token_id: int, + knowledge_asset_token_id: int, + paranet_service_name: str, + paranet_service_description: str, + paranet_service_addresses: list[Address], + ): + return self._register_paranet_service( + knowledge_collection_storage, + knowledge_collection_token_id, + knowledge_asset_token_id, + paranet_service_name, + paranet_service_description, + paranet_service_addresses, + ) + + def add_paranet_services( + self, + paranet_knowledge_collection_storage: str | Address, + paranet_knowledge_collection_token_id: int, + paranet_knowledge_asset_token_id: int, + services: list, + ): + return self._add_paranet_services( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + services, + ) + + def deploy_neuro_incentives_pool( + self, + is_native_reward: bool, + paranet_knowledge_collection_storage: str | Address, + paranet_knowledge_collection_token_id: int, + paranet_knowledge_asset_token_id: int, + trac_to_neuro_emission_multiplier: float, + paranet_operator_reward_percentage: float, + paranet_incentivization_proposal_voters_reward_percentage: float, + ): + return self._deploy_neuro_incentives_pool( + is_native_reward, + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + trac_to_neuro_emission_multiplier, + paranet_operator_reward_percentage, + paranet_incentivization_proposal_voters_reward_percentage, + ) + + def get_incentives_pool_address( + self, paranet_id: HexStr, incentives_pool_type: ParanetIncentivizationType + ): + return self._get_incentives_pool_address(paranet_id, incentives_pool_type) + + def is_knowledge_miner_registered(self, paranet_id: HexStr, address: Address): + return self._is_knowledge_miner_registered(paranet_id, address) + + def is_knowledge_collection_owner(self, owner: Address, id: int): + return self._is_knowledge_collection_owner(owner, id) + + def is_paranet_operator(self, operator_address: Address): + return self._is_paranet_operator(operator_address) + + def set_incentives_pool(self, incentives_pool_address: Address): + self.manager.blockchain_provider.set_incentives_pool(incentives_pool_address) + + def is_proposal_voter(self, address: Address): + return self._is_proposal_voter(address) + + def burn_knowledge_assets_tokens( + self, id: int, from_: Address, token_ids: list[int] + ): + return self._burn_knowledge_assets_tokens(id, from_, token_ids) + + def transfer_asset(self, from_: Address, to: Address, token_id: int): + return self._transfer_asset(from_, to, token_id, 1, Web3.to_bytes(hexstr="0x")) diff --git a/dkg/services/input_service.py b/dkg/services/input_service.py index e8147ed..25506de 100644 --- a/dkg/services/input_service.py +++ b/dkg/services/input_service.py @@ -3,6 +3,7 @@ ZERO_ADDRESS, DEFAULT_PROXIMITY_SCORE_FUNCTIONS_PAIR_IDS, ) +from dkg.dataclasses import ParanetNodesAccessPolicy, ParanetMinersAccessPolicy class InputService: @@ -59,6 +60,27 @@ def get_publish_finality_arguments(self, options): ), } + def get_paranet_create_arguments(self, options): + return { + "paranet_name": self.get_paranet_name(options), + "paranet_description": self.get_paranet_description(options), + "paranet_nodes_access_policy": self.get_paranet_nodes_access_policy( + options + ), + "paranet_miners_access_policy": self.get_paranet_miners_access_policy( + options + ), + } + + def get_paranet_create_service_arguments(self, options): + return { + "paranet_service_name": self.get_paranet_service_name(options), + "paranet_service_description": self.get_paranet_service_description( + options + ), + "paranet_service_addresses": self.get_paranet_service_addresses(options), + } + def get_max_number_of_retries(self, options): return ( options.get("max_number_of_retries") @@ -176,8 +198,30 @@ def get_score_function_id(self, options): return DEFAULT_PROXIMITY_SCORE_FUNCTIONS_PAIR_IDS[environment][blockchain_name] def get_repository(self, options): + return options.get("repository") or self.config.get("repository") or None + + def get_paranet_name(self, options): + return options.get("paranet_name") or None + + def get_paranet_description(self, options): + return options.get("paranet_description") or None + + def get_paranet_nodes_access_policy(self, options): + return ( + options.get("paranet_nodes_access_policy") or ParanetNodesAccessPolicy.OPEN + ) + + def get_paranet_miners_access_policy(self, options): return ( - options.get("repository") - or self.config.get("repository") - or DefaultParameters.REPOSITORY.value + options.get("paranet_miners_access_policy") + or ParanetMinersAccessPolicy.OPEN ) + + def get_paranet_service_name(self, options): + return options.get("paranet_service_name") or None + + def get_paranet_service_description(self, options): + return options.get("paranet_service_description") or None + + def get_paranet_service_addresses(self, options): + return options.get("paranet_service_addresses") or [] diff --git a/dkg/services/node_services/async_node_service.py b/dkg/services/node_services/async_node_service.py index 1641988..95a5299 100644 --- a/dkg/services/node_services/async_node_service.py +++ b/dkg/services/node_services/async_node_service.py @@ -1,7 +1,7 @@ from dkg.managers.async_manager import AsyncRequestManager from dkg.method import Method from dkg.constants import OperationStatuses, ErrorType, Status -from dkg.utils.node_request import NodeRequest +from dkg.request_managers.node_request import NodeRequest from dkg.modules.async_module import AsyncModule from typing import Dict, Any from dkg.types import UAL @@ -17,7 +17,6 @@ def __init__(self, manager: AsyncRequestManager): _get_operation_result = Method(NodeRequest.get_operation_result) _finality_status = Method(NodeRequest.finality_status) _ask = Method(NodeRequest.ask) - _get_bid_suggestion = Method(NodeRequest.bid_suggestion) _publish = Method(NodeRequest.publish) _get = Method(NodeRequest.get) _query = Method(NodeRequest.query) diff --git a/dkg/services/node_services/node_service.py b/dkg/services/node_services/node_service.py index e447055..a49d02c 100644 --- a/dkg/services/node_services/node_service.py +++ b/dkg/services/node_services/node_service.py @@ -6,7 +6,7 @@ from dkg.exceptions import ( OperationNotFinished, ) -from dkg.utils.node_request import ( +from dkg.request_managers.node_request import ( NodeRequest, validate_operation_status, ) diff --git a/dkg/utils/common.py b/dkg/utils/common.py new file mode 100644 index 0000000..a2decc5 --- /dev/null +++ b/dkg/utils/common.py @@ -0,0 +1,33 @@ +from eth_account.messages import encode_defunct +from eth_account import Account +from hexbytes import HexBytes + + +def get_operation_status_dict(operation_result, operation_id): + # Check if data exists and has errorType + operation_data = ( + {"status": operation_result.get("status"), **operation_result.get("data")} + if operation_result.get("data") + and operation_result.get("data", {}).get("errorType") + else {"status": operation_result.get("status")} + ) + + return {"operationId": operation_id, **operation_data} + + +def get_message_signer_address(dataset_root: str, signature: dict): + message = encode_defunct(HexBytes(dataset_root)) + r, s, v = signature.get("r"), signature.get("s"), signature.get("v") + r = r[2:] if r.startswith("0x") else r + s = s[2:] if s.startswith("0x") else s + + sig = "0x" + r + s + hex(v)[2:].zfill(2) + + return Account.recover_message(message, signature=sig) + + +def snake_to_camel(string: str) -> str: + splitted_string = string.split("_") + return splitted_string[0] + "".join( + token.capitalize() for token in splitted_string[1:] + ) diff --git a/dkg/utils/knowledge_asset_tools.py b/dkg/utils/knowledge_asset_tools.py deleted file mode 100644 index 2c2ac14..0000000 --- a/dkg/utils/knowledge_asset_tools.py +++ /dev/null @@ -1,5 +0,0 @@ -from uuid import uuid4 - - -def generate_named_node(): - return f"uuid:{uuid4()}" diff --git a/dkg/utils/knowledge_collection_tools.py b/dkg/utils/knowledge_collection_tools.py index 66a13b8..82d55eb 100644 --- a/dkg/utils/knowledge_collection_tools.py +++ b/dkg/utils/knowledge_collection_tools.py @@ -246,3 +246,39 @@ def solidity_packed_sha256(types: list[str], values: list) -> str: sha256_hash = hashlib.sha256(packed_data).hexdigest() return f"0x{sha256_hash}" + + +def generate_named_node(): + return f"uuid:{uuid4()}" + + +def process_content(content: str) -> list: + return [line.strip() for line in content.split("\n") if line.strip() != ""] + + +def to_jsonld(nquads: str): + options = { + "algorithm": "URDNA2015", + "format": "application/n-quads", + } + + return jsonld.from_rdf(nquads, options) + + +def to_nquads(content, input_format): + options = { + "algorithm": "URDNA2015", + "format": "application/n-quads", + } + + if input_format: + options["inputFormat"] = input_format + try: + jsonld_data = jsonld.from_rdf(content, options) + canonized = jsonld.to_rdf(jsonld_data, options) + + if isinstance(canonized, str): + return [line for line in canonized.split("\n") if line.strip()] + + except Exception as e: + raise ValueError(f"Error processing content: {e}") diff --git a/dkg/utils/merkle.py b/dkg/utils/merkle.py deleted file mode 100644 index f7a57af..0000000 --- a/dkg/utils/merkle.py +++ /dev/null @@ -1,173 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at - -# http://www.apache.org/licenses/LICENSE-2.0 - -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -import copy -import hashlib -from typing import Callable - -from dkg.exceptions import LeafNotInTree -from dkg.types import HexStr -from eth_abi.packed import encode_packed -from hexbytes import HexBytes -from web3 import Web3 - - -def solidity_keccak256(data: HexStr) -> HexStr: - bytes_hash: HexBytes = Web3.solidity_keccak( - ["bytes"], - [data], - ) - - return bytes_hash.to_0x_hex() - - -def hash_assertion_with_indexes( - leaves: list[str], - hash_function: str | Callable[[str], HexStr] = solidity_keccak256, - sort: bool = True, -) -> list[HexStr]: - if sort: - leaves.sort() - - return list( - map( - hash_function, - [ - encode_packed( - ["bytes32", "uint256"], - [Web3.solidity_keccak(["string"], [leaf]), i], - ) - for i, leaf in enumerate(leaves) - ], - ) - ) - - -class MerkleTree: - def __init__( - self, - leaves: list[str], - hash_function: str | Callable[[str], HexStr] = solidity_keccak256, - sort_leaves: bool = False, - sort_pairs: bool = False, - ): - self.hash_function = self._set_hash_function(hash_function) - self.sort_leaves = sort_leaves - self.sort_pairs = sort_pairs - self.leaves = self._process_leaves(leaves) - self.tree = self.build_tree() - - @property - def root(self) -> HexStr: - return self.tree[0][0] - - def build_tree(self) -> list[list[HexStr]]: - tree = [self.leaves] - - while len(level := tree[-1]) > 1: - next_level = [] - for h1, h2 in zip(level[::2], level[1::2] + [None]): - if h2: - next_level.append( - self.hash_function( - h1 + h2[2:] - if not self.sort_pairs - else "0x" + "".join(sorted([h1[2:], h2[2:]])) - ) - ) - else: - next_level.append(h1) - - tree.append(next_level) - - tree.reverse() - return tree - - def proof(self, leaf: HexStr, index: int | None = None) -> list[HexStr]: - if index is None: - for i, t_leaf in enumerate(self.leaves): - if leaf == t_leaf: - index = i - break - - if index is None: - raise LeafNotInTree(f"{leaf} is not a part of the Merkle Tree.") - - proof = [] - levels = copy.deepcopy(self.tree[:0:-1]) - for level in levels: - if (len(level) % 2) == 1: - level.append(level[-1]) - - if (index % 2) == 1: - proof.append(level[index - 1]) - else: - proof.append(level[index + 1]) - - index //= 2 - - return proof - - def verify(self, proof: list[HexStr], leaf: HexStr) -> bool: - if self.sort_pairs: - hash = leaf - for p in proof: - if hash == p: - continue - - hash = self.hash_function("".join(sorted([hash, p]))) - - else: - for i, t_leaf in enumerate(self.leaves): - if leaf == t_leaf: - index = i - break - - if index is None: - raise LeafNotInTree(f"{leaf} is not a part of the Merkle Tree.") - - hash = leaf - for p in proof: - if hash == p: - continue - - is_left = (index % 2) == 0 - hash = self.hash_function("".join([hash, p] if is_left else [p, hash])) - index //= 2 - - return hash == self.root - - def _process_leaves(self, leaves: list[str | HexStr]) -> list[HexStr]: - if self.sort_leaves: - leaves.sort() - - return leaves - - def _set_hash_function( - self, hash_function: str | Callable[[str], HexStr] - ) -> Callable[[str], HexStr]: - if ( - isinstance(hash_function, str) - and hash_function in hashlib.algorithms_available - ): - return lambda data: getattr(hashlib, hash_function)( - data.encode() - ).hexdigest() - elif isinstance(hash_function, Callable): - return hash_function - else: - raise ValueError() diff --git a/dkg/utils/metadata.py b/dkg/utils/metadata.py deleted file mode 100644 index 2644742..0000000 --- a/dkg/utils/metadata.py +++ /dev/null @@ -1,50 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at - -# http://www.apache.org/licenses/LICENSE-2.0 - -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -import hashlib -import json - -from dkg.types import Address, NQuads -from eth_abi.packed import encode_packed - - -def generate_assertion_metadata(assertion: NQuads) -> dict[str, int]: - return { - "size": len(json.dumps(assertion, separators=(",", ":")).encode("utf-8")), - "triples_number": len(assertion), - "chunks_number": len(assertion), # TODO: Change when chunking introduced - } - - -def generate_keyword(contract_address: Address, assertion_id: bytes) -> bytes: - return encode_packed( - ["address", "bytes32"], - [contract_address, assertion_id], - ) - - -def generate_agreement_id( - contract_address: Address, - token_id: int, - keyword: bytes, -) -> bytes: - return hashlib.sha256( - encode_packed( - ["address", "uint256", "bytes"], - [contract_address, token_id, keyword], - ) - ).digest() diff --git a/dkg/utils/rdf.py b/dkg/utils/rdf.py deleted file mode 100644 index b01548b..0000000 --- a/dkg/utils/rdf.py +++ /dev/null @@ -1,87 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at - -# http://www.apache.org/licenses/LICENSE-2.0 - -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -from typing import Literal - -from dkg.constants import ( - PRIVATE_ASSERTION_PREDICATE, - DEFAULT_RDF_FORMAT, - DEFAULT_CANON_ALGORITHM, -) -from dkg.exceptions import DatasetInputFormatNotSupported, InvalidDataset -from dkg.types import JSONLD, HexStr, NQuads -from dkg.utils.merkle import MerkleTree, hash_assertion_with_indexes -from pyld import jsonld - - -def normalize_dataset( - dataset: JSONLD | NQuads, - input_format: Literal["JSON-LD", "N-Quads"] = "JSON-LD", - output_format=DEFAULT_RDF_FORMAT, - algorithm=DEFAULT_CANON_ALGORITHM, -) -> NQuads: - normalization_options = { - "algorithm": algorithm, - "format": output_format, - } - - match input_format.lower(): - case "json-ld" | "jsonld": - pass - case "n-quads" | "nquads": - normalization_options["inputFormat"] = "application/n-quads" - case _: - raise DatasetInputFormatNotSupported( - f"Dataset input format isn't supported: {input_format}. " - "Supported formats: JSON-LD / N-Quads." - ) - - n_quads = jsonld.normalize(dataset, normalization_options) - assertion = [quad for quad in n_quads.split("\n") if quad] - - if not assertion: - raise InvalidDataset("Invalid dataset, no quads were extracted.") - - return assertion - - -def format_content( - content: dict[Literal["public", "private"], JSONLD], - type: Literal["JSON-LD", "N-Quads"] = "JSON-LD", -) -> dict[str, dict[str, HexStr | NQuads | int]]: - public_graph = {"@graph": []} - - if content.get("public", None): - public_graph["@graph"].append(content["public"]) - - if content.get("private", None): - private_assertion = normalize_dataset(content["private"], type) - private_assertion_id = MerkleTree( - hash_assertion_with_indexes(private_assertion), - sort_pairs=True, - ).root - - public_graph["@graph"].append( - {PRIVATE_ASSERTION_PREDICATE: private_assertion_id} - ) - - public_assertion = normalize_dataset(public_graph, type) - - return { - "public": public_assertion, - "private": private_assertion if content.get("private", None) else {}, - } diff --git a/dkg/utils/string_transformations.py b/dkg/utils/string_transformations.py deleted file mode 100644 index a84a635..0000000 --- a/dkg/utils/string_transformations.py +++ /dev/null @@ -1,23 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at - -# http://www.apache.org/licenses/LICENSE-2.0 - -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - - -def snake_to_camel(string: str) -> str: - splitted_string = string.split("_") - return splitted_string[0] + "".join( - token.capitalize() for token in splitted_string[1:] - ) diff --git a/dkg/utils/ual.py b/dkg/utils/ual.py index 4393fd8..9eeaf12 100644 --- a/dkg/utils/ual.py +++ b/dkg/utils/ual.py @@ -21,24 +21,84 @@ def format_ual( - blockchain: str, contract_address: Address | ChecksumAddress, token_id: int + blockchain: str, + contract_address: Address | ChecksumAddress, + knowledge_collection_token_id: int, + knowledge_asset_token_id: int | None = None, ) -> UAL: - return f"did:dkg:{blockchain.lower()}/{contract_address.lower()}/{token_id}" + ual = f"did:dkg:{blockchain.lower()}/{contract_address.lower()}/{knowledge_collection_token_id}" + return f"{ual}/{knowledge_asset_token_id}" if knowledge_asset_token_id else ual def parse_ual(ual: UAL) -> dict[str, str | Address | int]: if not ual.startswith("did:dkg:"): - raise ValidationError("Invalid UAL!") + raise ValidationError(f"Invalid UAL: {ual}. UAL should start with did:dkg:") args = ual.replace("did:dkg:", "").split("/") - if len(args) != 3: + knowledge_asset_token_id = None + if len(args) == 4: + ( + blockchain, + contract_address, + knowledge_collection_token_id, + knowledge_asset_token_id, + ) = args + elif len(args) == 3: + blockchain, contract_address, knowledge_collection_token_id = args + else: raise ValidationError("Invalid UAL!") - blockchain, contract_address, token_id = args - - return { + resolved_ual = { "blockchain": blockchain, "contract_address": Web3.to_checksum_address(contract_address), - "token_id": int(token_id), + "knowledge_collection_token_id": int(knowledge_collection_token_id), } + + if knowledge_asset_token_id: + resolved_ual["knowledge_asset_token_id"] = int(knowledge_asset_token_id) + + return resolved_ual + + +def get_paranet_ual_details(paranet_ual: UAL) -> dict[str, str | Address | int]: + parsed_ual = parse_ual(paranet_ual) + ( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + ) = ( + parsed_ual["contract_address"], + parsed_ual["knowledge_collection_token_id"], + parsed_ual.get("knowledge_asset_token_id", None), + ) + + if not paranet_knowledge_asset_token_id: + raise ValidationError( + "Invalid paranet UAL! Knowledge asset token id is required!" + ) + + return ( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + ) + + +def get_paranet_id(paranet_ual: UAL) -> bytes: + ( + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + ) = get_paranet_ual_details(paranet_ual) + + paranet_id = Web3.solidity_keccak( + ["address", "uint256", "uint256"], + [ + paranet_knowledge_collection_storage, + paranet_knowledge_collection_token_id, + paranet_knowledge_asset_token_id, + ], + ) + + return paranet_id diff --git a/examples/async_demo.py b/examples/async_demo.py index dffa96f..e3d643f 100644 --- a/examples/async_demo.py +++ b/examples/async_demo.py @@ -72,7 +72,6 @@ def print_json(json_dict: dict): "epochs_num": 2, "minimum_number_of_finalization_confirmations": 3, "minimum_number_of_node_replications": 1, - "token_amount": 100, }, ) print( @@ -91,7 +90,27 @@ def print_json(json_dict: dict): divider() - # This one is async + start_time = time.perf_counter() + transfer_result = await dkg.asset.transfer( + create_asset_result.get("UAL"), "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" + ) + print( + f"======================== ASSET TRANSFER in {time.perf_counter() - start_time} seconds" + ) + print_json(transfer_result) + + divider() + + # start_time = time.perf_counter() + # # Burns knowledge collections + # burn_result = await dkg.asset.burn(create_asset_result["UAL"], [1]) + # print( + # f"======================== ASSET BURN in {time.perf_counter() - start_time} seconds" + # ) + # print_json(burn_result) + + # divider() + start_time = time.perf_counter() query_operation_result = await dkg.graph.query( """ diff --git a/examples/async_paranets_demo.py b/examples/async_paranets_demo.py new file mode 100644 index 0000000..206b806 --- /dev/null +++ b/examples/async_paranets_demo.py @@ -0,0 +1,408 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +import asyncio +import json +from dkg import AsyncDKG +from dkg.constants import Environments, BlockchainIds +from dkg.providers import AsyncBlockchainProvider, AsyncNodeHTTPProvider +from dkg.dataclasses import ( + ParanetNodesAccessPolicy, + ParanetMinersAccessPolicy, +) + + +async def main(): + node_provider = AsyncNodeHTTPProvider(endpoint_uri="http://localhost:8900") + + # IMPORTANT: make sure that you have PRIVATE_KEY in .env so the blockchain provider can load it + blockchain_provider = AsyncBlockchainProvider( + Environments.DEVELOPMENT.value, + BlockchainIds.HARDHAT_1.value, + ) + + # here you can create your own custom values that will be applied to all the functions + config = { + "max_number_of_retries": 300, + "frequency": 2, + } + dkg = AsyncDKG(node_provider, blockchain_provider, config) + + def divider(): + print("==================================================") + print("==================================================") + print("==================================================") + + def print_json(json_dict: dict): + print(json.dumps(json_dict, indent=4)) + + divider() + + info_result = await dkg.node.info + + print("======================== NODE INFO RECEIVED") + print_json(info_result) + + paranet_content = { + "public": { + "@context": "https://www.schema.org", + "@id": "urn:us-cities:info:new-york", + "@type": "City", + "name": "New York", + "state": "New York", + "population": "8,336,817", + "area": "468.9 sq mi", + }, + "private": { + "@context": "https://www.schema.org", + "@id": "urn:us-cities:data:new-york", + "@type": "CityPrivateData", + "crimeRate": "Low", + "averageIncome": "$63,998", + "infrastructureScore": "8.5", + "relatedCities": [ + {"@id": "urn:us-cities:info:los-angeles", "name": "Los Angeles"}, + {"@id": "urn:us-cities:info:chicago", "name": "Chicago"}, + ], + }, + } + + create_paranet_knowledge_collection_result = await dkg.asset.create( + content=paranet_content, options={"epochs_num": 2} + ) + + print("======================== PARANET KNOWLEDGE COLLECTION CREATED") + print_json(create_paranet_knowledge_collection_result) + + divider() + + # Paranet UAL is a Knowledge Asset UAL (combination of Knowledge Collection UAL and Knowledge Asset token id) + paranet_ual = f"{create_paranet_knowledge_collection_result['UAL']}/1" + paranet_options = { + "paranet_name": "FirstParanet", + "paranet_description": "First ever paranet on DKG!", + "trac_to_neuro_emission_multiplier": 5, + "incentivization_proposal_voters_reward_percentage": 12.0, + "operator_reward_percentage": 10.0, + "paranet_nodes_access_policy": ParanetNodesAccessPolicy.OPEN, + "paranet_miners_access_policy": ParanetMinersAccessPolicy.OPEN, + } + + create_paranet_result = await dkg.paranet.create(paranet_ual, paranet_options) + + print("======================== PARANET REGISTERED") + print_json(create_paranet_result) + + divider() + + incentives_pool_params = dkg.paranet.NeuroWebIncentivesPoolParams( + neuro_emission_multiplier=1.1, operator_percentage=10.5, voters_percentage=5.5 + ) + deploy_incentives_contract_result = await dkg.paranet.deploy_incentives_contract( + paranet_ual, incentives_pool_params + ) + + print("======================== PARANET NEURO INCENTIVES POOL DEPLOYED") + print_json(deploy_incentives_contract_result) + + divider() + + incentives_pool_address = await dkg.paranet.get_incentives_pool_address(paranet_ual) + + print("======================== GOT PARANET NEURO INCENTIVES POOL ADDRESS") + print(incentives_pool_address) + + divider() + + incentives_amount = blockchain_provider.w3.to_wei(100, "ether") + await blockchain_provider.w3.eth.send_transaction( + { + "from": blockchain_provider.account.address, + "to": incentives_pool_address, + "value": incentives_amount, + } + ) + + print(f"======================== SENT {incentives_amount} TO THE INCENTIVES POOL") + + divider() + + service_content = { + "public": { + "@context": "https://www.schema.org", + "@id": "urn:us-cities:info:miami", + "@type": "City", + "name": "Miami", + "state": "Florida", + "population": "2,000,000", + "area": "135.2 sq mi", + }, + "private": { + "@context": "https://www.schema.org", + "@id": "urn:us-cities:data:miami", + "@type": "CityPrivateData", + "crimeRate": "Low", + "averageIncome": "$100,998", + "infrastructureScore": "7.5", + "relatedCities": [ + {"@id": "urn:us-cities:info:austin", "name": "Austin"}, + {"@id": "urn:us-cities:info:seattle", "name": "Seattle"}, + ], + }, + } + + create_paranet_service_kc_result = await dkg.asset.create( + content=service_content, + options={"epochs_num": 2}, + ) + + print("======================== PARANET SERVICE KNOWLEDGE COLLECTION CREATED") + print_json(create_paranet_service_kc_result) + + divider() + # Paranet service UAL is a Knowledge Asset UAL (combination of Knowledge Collection UAL and Knowledge Asset token id) + paranet_service_ual = f"{create_paranet_service_kc_result['UAL']}/1" + + submit_to_paranet = await dkg.asset.submit_to_paranet( + paranet_service_ual, paranet_ual + ) + + print("======================== SUBMITED TO PARANET") + print_json(submit_to_paranet) + + divider() + + create_paranet_service_result = await dkg.paranet.create_service( + ual=paranet_service_ual, + options={ + "paranet_service_name": "FKPS", + "paranet_service_description": "Fast Knowledge Processing Service", + "paranet_service_addresses": [], + }, + ) + + print("======================== PARANET SERVICE CREATED") + print_json(create_paranet_service_result) + + divider() + + add_services_result = await dkg.paranet.add_services( + paranet_ual, [paranet_service_ual] + ) + + print("======================== ADDED PARANET SERVICES") + print_json(add_services_result) + + divider() + + is_knowledge_miner = await dkg.paranet.is_knowledge_miner(paranet_ual) + print(f"Is Knowledge Miner? {str(is_knowledge_miner)}") + + is_operator = await dkg.paranet.is_operator(paranet_ual) + print(f"Is Operator? {str(is_operator)}") + + is_voter = await dkg.paranet.is_voter(paranet_ual) + print(f"Is Voter? {str(is_voter)}") + + divider() + + # def print_reward_stats(is_voter: bool = False): + # knowledge_miner_reward = dkg.paranet.calculate_claimable_miner_reward_amount( + # paranet_ual + # ) + # operator_reward = dkg.paranet.calculate_claimable_operator_reward_amount( + # paranet_ual + # ) + + # print( + # f"Claimable Knowledge Miner Reward for the Current Wallet: {knowledge_miner_reward}" + # ) + # print( + # f"Claimable Paranet Operator Reward for the Current Wallet: {operator_reward}" + # ) + # if is_voter: + # voter_rewards = dkg.paranet.calculate_claimable_voter_reward_amount(paranet_ual) + # print( + # f"Claimable Proposal Voter Reward for the Current Wallet: {voter_rewards}" + # ) + + # divider() + + # all_knowledge_miners_reward = ( + # dkg.paranet.calculate_all_claimable_miner_rewards_amount(paranet_ual) + # ) + # all_voters_reward = dkg.paranet.calculate_all_claimable_voters_reward_amount( + # paranet_ual + # ) + + # print(f"Claimable All Knowledge Miners Reward: {all_knowledge_miners_reward}") + # print(f"Claimable Paranet Operator Reward: {operator_reward}") + # print(f"Claimable All Proposal Voters Reward: {all_voters_reward}") + + # print_reward_stats(is_voter) + + # divider() + + # claim_miner_reward_result = dkg.paranet.claim_miner_reward(paranet_ual) + + # print("======================== KNOWLEDGE MINER REWARD CLAIMED") + # print_json(claim_miner_reward_result) + + # divider() + + # claim_operator_reward_result = dkg.paranet.claim_operator_reward(paranet_ual) + + # print("======================== PARANET OPERATOR REWARD CLAIMED") + # print(claim_operator_reward_result) + + # divider() + + # print_reward_stats() + + # divider() + + denver_content = { + "public": { + "@context": "https://www.schema.org", + "@id": "urn:us-cities:info:denver", + "@type": "City", + "name": "Denver", + "state": "Colorado", + "population": "700,000", + "area": "153.3 sq mi", + }, + "private": { + "@context": "https://www.schema.org", + "@id": "urn:us-cities:data:denver", + "@type": "CityPrivateData", + "crimeRate": "Low", + "averageIncome": "$50,998", + "infrastructureScore": "6.5", + "relatedCities": [ + {"@id": "urn:us-cities:info:boston", "name": "Boston"}, + {"@id": "urn:us-cities:info:chicago", "name": "Chicago"}, + ], + }, + } + + create_collection_result = await dkg.asset.create( + content=denver_content, options={"epochs_num": 2} + ) + + print("======================== KNOWLEDGE COLLECTION #1 CREATED") + print_json(create_collection_result) + + divider() + + submit_to_paranet_result = await dkg.asset.submit_to_paranet( + create_collection_result["UAL"], paranet_ual + ) + + print("======================== KNOWLEDGE COLLECTION #1 SUBMITED TO THE PARANET") + print_json(submit_to_paranet_result) + + divider() + + dallas_content = { + "public": { + "@context": "https://www.schema.org", + "@id": "urn:us-cities:info:dallas", + "@type": "City", + "name": "Dallas", + "state": "Texas", + "population": "1,343,573", + "area": "386.5 sq mi", + }, + "private": { + "@context": "https://www.schema.org", + "@id": "urn:us-cities:data:dallas", + "@type": "CityPrivateData", + "crimeRate": "Low", + "averageIncome": "$80,998", + "infrastructureScore": "7.5", + "relatedCities": [ + {"@id": "urn:us-cities:info:austin", "name": "Austin"}, + {"@id": "urn:us-cities:info:houston", "name": "Houston"}, + ], + }, + } + + create_collection_result2 = await dkg.asset.create( + content=dallas_content, options={"epochs_num": 2} + ) + print("======================== KNOWLEDGE COLLECTION #2 CREATED") + print_json(create_collection_result2) + + submit_to_paranet_result2 = await dkg.asset.submit_to_paranet( + create_collection_result2["UAL"], paranet_ual + ) + + print("======================== KNOWLEDGE COLLECTION #2 SUBMITTED TO THE PARANET") + print_json(submit_to_paranet_result2) + + divider() + + # IMPORTANT: For queries to work, you need to add assetSync to your node's .origintrail_noderc file. + # How to: https://docs.origintrail.io/dkg-v6-previous-version/node-setup-instructions/sync-a-dkg-paranet + query_where_denver = """ + PREFIX schema: + SELECT DISTINCT ?graphName + WHERE { + GRAPH ?graphName { + ?s schema:name "Denver" . + } + } + """ + query_result = await dkg.graph.query( + query=query_where_denver, options={"paranet_ual": paranet_ual} + ) + + print("======================== QUERY PARANET REPOSITORY RESULT") + print_json(query_result) + + divider() + + federated_query = f""" + PREFIX schema: + SELECT DISTINCT ?s ?state1 ?name1 ?s2 ?state2 ?name2 ?population1 + WHERE {{ + ?s schema:state ?state1 . + ?s schema:name ?name1 . + ?s schema:population ?population1 . + + SERVICE <{paranet_ual}> {{ + ?s2 schema:state "Colorado" . + ?s2 schema:name "Denver" . + ?s2 schema:state ?state2 . + ?s2 schema:name ?name2 . + }} + + filter(contains(str(?name2), "Denver")) + }} + """ + query_result = await dkg.graph.query( + query=federated_query, options={"paranet_ual": paranet_ual} + ) + + print("======================== FEDERATED QUERY RESULT") + print_json(query_result) + + divider() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/examples/demo.py b/examples/demo.py index 00060d8..451b2ce 100644 --- a/examples/demo.py +++ b/examples/demo.py @@ -90,7 +90,6 @@ def print_json(json_dict: dict): "epochs_num": 2, "minimum_number_of_finalization_confirmations": 3, "minimum_number_of_node_replications": 1, - "token_amount": 100, }, ) print( @@ -109,6 +108,27 @@ def print_json(json_dict: dict): divider() +start_time = time.perf_counter() +transfer_result = dkg.asset.transfer( + create_asset_result.get("UAL"), "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" +) +print( + f"======================== ASSET TRANSFER in {time.perf_counter() - start_time} seconds" +) +print_json(transfer_result) + +divider() + +# start_time = time.perf_counter() +# # Burns knowledge collections +# burn_result = dkg.asset.burn(create_asset_result["UAL"], [1]) +# print( +# f"======================== ASSET BURN in {time.perf_counter() - start_time} seconds" +# ) +# print_json(burn_result) + +# divider() + start_time = time.perf_counter() query_operation_result = dkg.graph.query( """ diff --git a/examples/paranets_demo.py b/examples/paranets_demo.py index 9c42404..2cd9da6 100644 --- a/examples/paranets_demo.py +++ b/examples/paranets_demo.py @@ -17,21 +17,29 @@ import json -from hexbytes import HexBytes from dkg import DKG from dkg.providers import BlockchainProvider, NodeHTTPProvider -from dkg.dataclasses import ParanetNodesAccessPolicy, ParanetMinersAccessPolicy +from dkg.dataclasses import ( + ParanetNodesAccessPolicy, + ParanetMinersAccessPolicy, +) from dkg.constants import Environments, BlockchainIds node_provider = NodeHTTPProvider("http://localhost:8900") +# IMPORTANT: make sure that you have PRIVATE_KEY in .env so the blockchain provider can load it blockchain_provider = BlockchainProvider( - Environments.DEVELOPMENT.value, - BlockchainIds.HARDHAT_1.value, - ) + Environments.DEVELOPMENT.value, + BlockchainIds.HARDHAT_1.value, +) -dkg = DKG(node_provider, blockchain_provider) +# here you can create your own custom values that will be applied to all the functions +config = { + "max_number_of_retries": 300, + "frequency": 2, +} +dkg = DKG(node_provider, blockchain_provider, config) def divider(): @@ -41,102 +49,70 @@ def divider(): def print_json(json_dict: dict): - def convert_hexbytes(data): - if isinstance(data, dict): - return {k: convert_hexbytes(v) for k, v in data.items()} - elif isinstance(data, list): - return [convert_hexbytes(i) for i in data] - elif isinstance(data, HexBytes): - return data.to_0x_hex() - else: - return data - - serializable_dict = convert_hexbytes(json_dict) - print(json.dumps(serializable_dict, indent=4)) - - -divider() + print(json.dumps(json_dict, indent=4)) -paranet_data = { - "public": { - "@context": ["http://schema.org"], - "@id": "uuid:1", - "company": "OT", - "city": {"@id": "uuid:belgrade"}, - } -} - -create_paranet_knowledge_collection_result = dkg.asset.create(paranet_data, 1) - -print("======================== PARANET KNOWLEDGE COLLECTION CREATED") -print_json(create_paranet_knowledge_collection_result) divider() -paranet_ual = create_paranet_knowledge_collection_result["UAL"] -create_paranet_result = dkg.paranet.create( - paranet_ual, - "TestParanet", - "TestParanetDescription", - ParanetNodesAccessPolicy.OPEN, - ParanetMinersAccessPolicy.OPEN, -) - -print("======================== PARANET CREATED") -print_json(create_paranet_result) +info_result = dkg.node.info -divider() +print("======================== NODE INFO RECEIVED") +print_json(info_result) -paranet_service_data = { +paranet_content = { "public": { - "@context": ["http://schema.org"], - "@id": "uuid:2", - "service": "AI Agent Bob", - "model": {"@id": "uuid:gpt4"}, - } + "@context": "https://www.schema.org", + "@id": "urn:us-cities:info:new-york", + "@type": "City", + "name": "New York", + "state": "New York", + "population": "8,336,817", + "area": "468.9 sq mi", + }, + "private": { + "@context": "https://www.schema.org", + "@id": "urn:us-cities:data:new-york", + "@type": "CityPrivateData", + "crimeRate": "Low", + "averageIncome": "$63,998", + "infrastructureScore": "8.5", + "relatedCities": [ + {"@id": "urn:us-cities:info:los-angeles", "name": "Los Angeles"}, + {"@id": "urn:us-cities:info:chicago", "name": "Chicago"}, + ], + }, } -create_paranet_service_knowledge_collection_result = dkg.asset.create( - paranet_service_data, 1 +create_paranet_knowledge_collection_result = dkg.asset.create( + content=paranet_content, options={"epochs_num": 2} ) -print("======================== PARANET SERVICE KNOWLEDGE COLLECTION CREATED") -print_json(create_paranet_service_knowledge_collection_result) - -divider() -paranet_service_ual = create_paranet_service_knowledge_collection_result["UAL"] - - -submit_to_paranet = dkg.asset.submit_to_paranet(paranet_service_ual, paranet_ual) - -print("======================== SUBMITED TO PARANET") -print_json(submit_to_paranet) +print("======================== PARANET KNOWLEDGE COLLECTION CREATED") +print_json(create_paranet_knowledge_collection_result) divider() -create_paranet_service_result = dkg.paranet.create_service( - paranet_service_ual, - "TestParanetService", - "TestParanetServiceDescription", - ["0x03C094044301E082468876634F0b209E11d98452"], -) - -print("======================== PARANET SERVICE CREATED") -print_json(create_paranet_service_result) - -divider() +# Paranet UAL is a Knowledge Asset UAL (combination of Knowledge Collection UAL and Knowledge Asset token id) +paranet_ual = f"{create_paranet_knowledge_collection_result['UAL']}/1" +paranet_options = { + "paranet_name": "FirstParanet", + "paranet_description": "First ever paranet on DKG!", + "trac_to_neuro_emission_multiplier": 5, + "incentivization_proposal_voters_reward_percentage": 12.0, + "operator_reward_percentage": 10.0, + "paranet_nodes_access_policy": ParanetNodesAccessPolicy.OPEN, + "paranet_miners_access_policy": ParanetMinersAccessPolicy.OPEN, +} -add_services_result = dkg.paranet.add_services(paranet_ual, [paranet_service_ual]) +create_paranet_result = dkg.paranet.create(paranet_ual, paranet_options) -print("======================== ADDED PARANET SERVICES") -print_json(add_services_result) +print("======================== PARANET REGISTERED") +print_json(create_paranet_result) divider() incentives_pool_params = dkg.paranet.NeuroWebIncentivesPoolParams( - neuro_emission_multiplier=1.1, - operator_percentage=10.5, - voters_percentage=5.5, + neuro_emission_multiplier=1.1, operator_percentage=10.5, voters_percentage=5.5 ) deploy_incentives_contract_result = dkg.paranet.deploy_incentives_contract( paranet_ual, incentives_pool_params @@ -147,6 +123,7 @@ def convert_hexbytes(data): divider() + incentives_pool_address = dkg.paranet.get_incentives_pool_address(paranet_ual) print("======================== GOT PARANET NEURO INCENTIVES POOL ADDRESS") @@ -167,161 +144,260 @@ def convert_hexbytes(data): divider() -is_knowledge_miner = dkg.paranet.is_knowledge_miner(paranet_ual) -is_operator = dkg.paranet.is_operator(paranet_ual) -is_voter = dkg.paranet.is_voter(paranet_ual) +service_content = { + "public": { + "@context": "https://www.schema.org", + "@id": "urn:us-cities:info:miami", + "@type": "City", + "name": "Miami", + "state": "Florida", + "population": "2,000,000", + "area": "135.2 sq mi", + }, + "private": { + "@context": "https://www.schema.org", + "@id": "urn:us-cities:data:miami", + "@type": "CityPrivateData", + "crimeRate": "Low", + "averageIncome": "$100,998", + "infrastructureScore": "7.5", + "relatedCities": [ + {"@id": "urn:us-cities:info:austin", "name": "Austin"}, + {"@id": "urn:us-cities:info:seattle", "name": "Seattle"}, + ], + }, +} -print(f"Is Knowledge Miner? {str(is_knowledge_miner)}") -print(f"Is Operator? {str(is_operator)}") -print(f"Is Voter? {str(is_voter)}") +create_paranet_service_kc_result = dkg.asset.create( + content=service_content, options={"epochs_num": 2} +) + +print("======================== PARANET SERVICE KNOWLEDGE COLLECTION CREATED") +print_json(create_paranet_service_kc_result) divider() +# Paranet service UAL is a Knowledge Asset UAL (combination of Knowledge Collection UAL and Knowledge Asset token id) +paranet_service_ual = f"{create_paranet_service_kc_result['UAL']}/1" +submit_to_paranet = dkg.asset.submit_to_paranet(paranet_service_ual, paranet_ual) -def print_reward_stats(is_voter: bool = False): - knowledge_miner_reward = dkg.paranet.calculate_claimable_miner_reward_amount( - paranet_ual - ) - operator_reward = dkg.paranet.calculate_claimable_operator_reward_amount( - paranet_ual - ) +print("======================== SUBMITED TO PARANET") +print_json(submit_to_paranet) - print( - f"Claimable Knowledge Miner Reward for the Current Wallet: {knowledge_miner_reward}" - ) - print( - f"Claimable Paranet Operator Reward for the Current Wallet: {operator_reward}" - ) - if is_voter: - voter_rewards = dkg.paranet.calculate_claimable_voter_reward_amount(paranet_ual) - print( - f"Claimable Proposal Voter Reward for the Current Wallet: {voter_rewards}" - ) +divider() - divider() +create_paranet_service_result = dkg.paranet.create_service( + ual=paranet_service_ual, + options={ + "paranet_service_name": "FKPS", + "paranet_service_description": "Fast Knowledge Processing Service", + "paranet_service_addresses": [], + }, +) - all_knowledge_miners_reward = ( - dkg.paranet.calculate_all_claimable_miner_rewards_amount(paranet_ual) - ) - all_voters_reward = dkg.paranet.calculate_all_claimable_voters_reward_amount( - paranet_ual - ) +print("======================== PARANET SERVICE CREATED") +print_json(create_paranet_service_result) - print(f"Claimable All Knowledge Miners Reward: {all_knowledge_miners_reward}") - print(f"Claimable Paranet Operator Reward: {operator_reward}") - print(f"Claimable All Proposal Voters Reward: {all_voters_reward}") +divider() +add_services_result = dkg.paranet.add_services(paranet_ual, [paranet_service_ual]) -print_reward_stats(is_voter) +print("======================== ADDED PARANET SERVICES") +print_json(add_services_result) divider() -kc1 = { - "public": { - "@context": ["http://schema.org"], - "@id": "uuid:3", - "company": "KA1-Company", - "user": {"@id": "uuid:user:1"}, - "city": {"@id": "uuid:belgrade"}, - } -} +is_knowledge_miner = dkg.paranet.is_knowledge_miner(paranet_ual) +print(f"Is Knowledge Miner? {str(is_knowledge_miner)}") -create_submit_kc1_result = dkg.asset.create( - kc1, - 1, - 100000000000000000000, - paranet_ual=paranet_ual, -) +is_operator = dkg.paranet.is_operator(paranet_ual) +print(f"Is Operator? {str(is_operator)}") -print( - "======================== KNOWLEDGE ASSET #1 CREATED AND SUBMITTED TO THE PARANET" -) -print_json(create_submit_kc1_result) +is_voter = dkg.paranet.is_voter(paranet_ual) +print(f"Is Voter? {str(is_voter)}") divider() -submit_to_paranet_result2 = dkg.asset.submit_to_paranet(create_submit_kc1_result["UAL"], paranet_ual) - -print("======================== SUBMITED TO PARANET") -print_json(submit_to_paranet_result2) +# def print_reward_stats(is_voter: bool = False): +# knowledge_miner_reward = dkg.paranet.calculate_claimable_miner_reward_amount( +# paranet_ual +# ) +# operator_reward = dkg.paranet.calculate_claimable_operator_reward_amount( +# paranet_ual +# ) + +# print( +# f"Claimable Knowledge Miner Reward for the Current Wallet: {knowledge_miner_reward}" +# ) +# print( +# f"Claimable Paranet Operator Reward for the Current Wallet: {operator_reward}" +# ) +# if is_voter: +# voter_rewards = dkg.paranet.calculate_claimable_voter_reward_amount(paranet_ual) +# print( +# f"Claimable Proposal Voter Reward for the Current Wallet: {voter_rewards}" +# ) + +# divider() + +# all_knowledge_miners_reward = ( +# dkg.paranet.calculate_all_claimable_miner_rewards_amount(paranet_ual) +# ) +# all_voters_reward = dkg.paranet.calculate_all_claimable_voters_reward_amount( +# paranet_ual +# ) + +# print(f"Claimable All Knowledge Miners Reward: {all_knowledge_miners_reward}") +# print(f"Claimable Paranet Operator Reward: {operator_reward}") +# print(f"Claimable All Proposal Voters Reward: {all_voters_reward}") + + +# print_reward_stats(is_voter) -divider() +# divider() -kc2 = { - "public": { - "@context": ["http://schema.org"], - "@id": "uuid:4", - "company": "KA2-Company", - "user": {"@id": "uuid:user:2"}, - "city": {"@id": "uuid:madrid"}, - } -} +# claim_miner_reward_result = dkg.paranet.claim_miner_reward(paranet_ual) -create_kc2_result = dkg.asset.create(kc2, 1, 20000000000000000000) +# print("======================== KNOWLEDGE MINER REWARD CLAIMED") +# print_json(claim_miner_reward_result) -print("======================== KNOWLEDGE ASSET #2 CREATED") -print_json(create_kc2_result) +# divider() -kc2_ual = create_kc2_result["UAL"] -submit_kc2_result = dkg.asset.submit_to_paranet(kc2_ual, paranet_ual) +# claim_operator_reward_result = dkg.paranet.claim_operator_reward(paranet_ual) -print("======================== KNOWLEDGE ASSET #2 SUBMITTED TO THE PARANET") -print_json(submit_kc2_result) +# print("======================== PARANET OPERATOR REWARD CLAIMED") +# print(claim_operator_reward_result) # divider() -# federated_query = """ -# PREFIX schema: -# SELECT DISTINCT ?s ?city1 ?user1 ?s2 ?city2 ?user2 ?company1 -# WHERE {{ -# ?s schema:city ?city1 . -# ?s schema:company ?company1 . -# ?s schema:user ?user1; - -# SERVICE <{ual}> {{ -# ?s2 schema:city ?city2 . -# ?s2 schema:user ?user2; -# }} - -# filter(contains(str(?city2), "belgrade")) -# }} -# """ -# query_result = dkg.graph.query( -# federated_query.format(ual=kc2_ual), -# paranet_ual, -# ) - -# print("======================== GOT FEDERATED QUERY RESULT") -# print(query_result) +# print_reward_stats() divider() -is_knowledge_miner = dkg.paranet.is_knowledge_miner(paranet_ual) -is_operator = dkg.paranet.is_operator(paranet_ual) -is_voter = dkg.paranet.is_voter(paranet_ual) +denver_content = { + "public": { + "@context": "https://www.schema.org", + "@id": "urn:us-cities:info:denver", + "@type": "City", + "name": "Denver", + "state": "Colorado", + "population": "700,000", + "area": "153.3 sq mi", + }, + "private": { + "@context": "https://www.schema.org", + "@id": "urn:us-cities:data:denver", + "@type": "CityPrivateData", + "crimeRate": "Low", + "averageIncome": "$50,998", + "infrastructureScore": "6.5", + "relatedCities": [ + {"@id": "urn:us-cities:info:boston", "name": "Boston"}, + {"@id": "urn:us-cities:info:chicago", "name": "Chicago"}, + ], + }, +} -print(f"Is Knowledge Miner? {str(is_knowledge_miner)}") -print(f"Is Operator? {str(is_operator)}") -print(f"Is Voter? {str(is_voter)}") +create_collection_result = dkg.asset.create( + content=denver_content, options={"epochs_num": 2} +) + +print("======================== KNOWLEDGE COLLECTION #1 CREATED") +print_json(create_collection_result) divider() -print_reward_stats(is_voter) +submit_to_paranet_result = dkg.asset.submit_to_paranet( + create_collection_result["UAL"], paranet_ual +) + +print("======================== KNOWLEDGE COLLECTION #1 SUBMITED TO THE PARANET") +print_json(submit_to_paranet_result) divider() -claim_miner_reward_result = dkg.paranet.claim_miner_reward(paranet_ual) +dallas_content = { + "public": { + "@context": "https://www.schema.org", + "@id": "urn:us-cities:info:dallas", + "@type": "City", + "name": "Dallas", + "state": "Texas", + "population": "1,343,573", + "area": "386.5 sq mi", + }, + "private": { + "@context": "https://www.schema.org", + "@id": "urn:us-cities:data:dallas", + "@type": "CityPrivateData", + "crimeRate": "Low", + "averageIncome": "$80,998", + "infrastructureScore": "7.5", + "relatedCities": [ + {"@id": "urn:us-cities:info:austin", "name": "Austin"}, + {"@id": "urn:us-cities:info:houston", "name": "Houston"}, + ], + }, +} + +create_collection_result2 = dkg.asset.create( + content=dallas_content, options={"epochs_num": 2} +) +print("======================== KNOWLEDGE COLLECTION #2 CREATED") +print_json(create_collection_result2) -print("======================== KNOWLEDGE MINER REWARD CLAIMED") -print_json(claim_miner_reward_result) +submit_to_paranet_result2 = dkg.asset.submit_to_paranet( + create_collection_result2["UAL"], paranet_ual +) + +print("======================== KNOWLEDGE COLLECTION #2 SUBMITTED TO THE PARANET") +print_json(submit_to_paranet_result2) divider() -claim_operator_reward_result = dkg.paranet.claim_operator_reward(paranet_ual) +# IMPORTANT: For queries to work, you need to add assetSync to your node's .origintrail_noderc file. +# How to: https://docs.origintrail.io/dkg-v6-previous-version/node-setup-instructions/sync-a-dkg-paranet +query_where_denver = """ +PREFIX schema: +SELECT DISTINCT ?graphName +WHERE { + GRAPH ?graphName { + ?s schema:name "Denver" . + } +} +""" +query_result = dkg.graph.query( + query=query_where_denver, options={"paranet_ual": paranet_ual} +) -print("======================== PARANET OPERATOR REWARD CLAIMED") -print(claim_operator_reward_result) +print("======================== QUERY PARANET REPOSITORY RESULT") +print_json(query_result) divider() -print_reward_stats() +federated_query = f""" +PREFIX schema: +SELECT DISTINCT ?s ?state1 ?name1 ?s2 ?state2 ?name2 ?population1 +WHERE {{ + ?s schema:state ?state1 . + ?s schema:name ?name1 . + ?s schema:population ?population1 . + + SERVICE <{paranet_ual}> {{ + ?s2 schema:state "Colorado" . + ?s2 schema:name "Denver" . + ?s2 schema:state ?state2 . + ?s2 schema:name ?name2 . + }} + + filter(contains(str(?name2), "Denver")) +}} +""" +query_result = dkg.graph.query( + query=federated_query, options={"paranet_ual": paranet_ual} +) + +print("======================== FEDERATED QUERY RESULT") +print_json(query_result) + +divider() diff --git a/pyproject.toml b/pyproject.toml index 26cd14a..8146f9e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "dkg" -version = "8.0.1" +version = "8.0.2" description = "Python library for interacting with the OriginTrail Decentralized Knowledge Graph" authors = ["Uladzislau Hubar , Zvonimir Sculac "] license = "Apache-2.0"