From f5669f7a3e9e88d368b06024ae6836c56391dd52 Mon Sep 17 00:00:00 2001 From: Uladzislau Hubar Date: Tue, 16 Jul 2024 17:30:51 +0700 Subject: [PATCH] Added possibility to mine Paranet KnowledgeAsset for someone --- abi/ContentAssetV2.json | 7 +- abi/Paranet.json | 76 ++++++++++++++++ contracts/v2/assets/ContentAsset.sol | 34 +++++-- contracts/v2/paranets/Paranet.sol | 127 ++++++++++++++++----------- package-lock.json | 4 +- package.json | 2 +- test/v2/unit/Paranet.test.ts | 90 ++++++++++++++++++- 7 files changed, 274 insertions(+), 66 deletions(-) diff --git a/abi/ContentAssetV2.json b/abi/ContentAssetV2.json index e9f97705..32e116e6 100644 --- a/abi/ContentAssetV2.json +++ b/abi/ContentAssetV2.json @@ -435,7 +435,12 @@ "inputs": [ { "internalType": "address", - "name": "originalSender", + "name": "minter", + "type": "address" + }, + { + "internalType": "address", + "name": "payer", "type": "address" }, { diff --git a/abi/Paranet.json b/abi/Paranet.json index 7eca7ac3..15ce2ba6 100644 --- a/abi/Paranet.json +++ b/abi/Paranet.json @@ -511,6 +511,82 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "paranetKAStorageContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "paranetKATokenId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "assertionId", + "type": "bytes32" + }, + { + "internalType": "uint128", + "name": "size", + "type": "uint128" + }, + { + "internalType": "uint32", + "name": "triplesNumber", + "type": "uint32" + }, + { + "internalType": "uint96", + "name": "chunksNumber", + "type": "uint96" + }, + { + "internalType": "uint16", + "name": "epochsNumber", + "type": "uint16" + }, + { + "internalType": "uint96", + "name": "tokenAmount", + "type": "uint96" + }, + { + "internalType": "uint8", + "name": "scoreFunctionId", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "immutable_", + "type": "bool" + } + ], + "internalType": "struct ContentAssetStructs.AssetInputArgs", + "name": "knowledgeAssetArgs", + "type": "tuple" + }, + { + "internalType": "address", + "name": "miner", + "type": "address" + } + ], + "name": "mintKnowledgeAssetFor", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "name", diff --git a/contracts/v2/assets/ContentAsset.sol b/contracts/v2/assets/ContentAsset.sol index 79b4a527..53b0f1c9 100644 --- a/contracts/v2/assets/ContentAsset.sol +++ b/contracts/v2/assets/ContentAsset.sol @@ -19,6 +19,7 @@ import {Versioned} from "../../v1/interface/Versioned.sol"; import {ContentAssetStructs} from "../../v1/structs/assets/ContentAssetStructs.sol"; import {ServiceAgreementStructsV1} from "../../v1/structs/ServiceAgreementStructsV1.sol"; import {ContentAssetErrors} from "../errors/assets/ContentAssetErrors.sol"; +import {ParanetErrors} from "../errors/paranets/ParanetErrors.sol"; import {HASH_FUNCTION_ID} from "../../v1/constants/assets/ContentAssetConstants.sol"; import {LOG2PLDSF_ID, LINEAR_SUM_ID} from "../../v1/constants/ScoringConstants.sol"; @@ -47,7 +48,7 @@ contract ContentAssetV2 is Named, Versioned, HubDependentV2, Initializable { event AssetUpdatePaymentIncreased(address indexed assetContract, uint256 indexed tokenId, uint96 tokenAmount); string private constant _NAME = "ContentAsset"; - string private constant _VERSION = "2.1.0"; + string private constant _VERSION = "2.2.0"; Assertion public assertionContract; HashingProxy public hashingProxy; @@ -103,6 +104,7 @@ contract ContentAssetV2 is Named, Versioned, HubDependentV2, Initializable { function createAsset(ContentAssetStructs.AssetInputArgs calldata args) external returns (uint256) { return _createAsset( + msg.sender, msg.sender, args.assertionId, args.size, @@ -116,12 +118,14 @@ contract ContentAssetV2 is Named, Versioned, HubDependentV2, Initializable { } function createAssetFromContract( - address originalSender, + address minter, + address payer, ContentAssetStructs.AssetInputArgs calldata args ) external onlyContracts returns (uint256) { return _createAsset( - originalSender, + minter, + payer, args.assertionId, args.size, args.triplesNumber, @@ -145,6 +149,7 @@ contract ContentAssetV2 is Named, Versioned, HubDependentV2, Initializable { ) external returns (uint256) { return _createAsset( + msg.sender, msg.sender, assertionId, size, @@ -455,13 +460,28 @@ contract ContentAssetV2 is Named, Versioned, HubDependentV2, Initializable { revert ContentAssetErrors.AssetExpired(tokenId); } + ParanetKnowledgeAssetsRegistry pkar = paranetKnowledgeAssetsRegistry; + + if (pkar.isParanetKnowledgeAsset(keccak256(abi.encodePacked(contentAssetStorageAddress, tokenId)))) { + bytes32 paranetId = pkar.getParanetId(keccak256(abi.encodePacked(contentAssetStorageAddress, tokenId))); + + // Add additional tokenAmount to the UpdatingKnowledgeAssets in the KnowledgeMinersRegistry + paranetKnowledgeMinersRegistry.addUpdatingKnowledgeAssetUpdateTokenAmount( + msg.sender, + paranetId, + keccak256(abi.encodePacked(contentAssetStorageAddress, tokenId, unfinalizedState)), + tokenAmount + ); + } + sasV1.addUpdateTokens(msg.sender, agreementId, tokenAmount); emit AssetUpdatePaymentIncreased(contentAssetStorageAddress, tokenId, tokenAmount); } function _createAsset( - address originalSender, + address minter, + address payer, bytes32 assertionId, uint128 size, uint32 triplesNumber, @@ -474,10 +494,10 @@ contract ContentAssetV2 is Named, Versioned, HubDependentV2, Initializable { ContentAssetStorage cas = contentAssetStorage; uint256 tokenId = cas.generateTokenId(); - cas.mint(originalSender, tokenId); + cas.mint(minter, tokenId); assertionContract.createAssertion(assertionId, size, triplesNumber, chunksNumber); - cas.setAssertionIssuer(tokenId, assertionId, originalSender); + cas.setAssertionIssuer(tokenId, assertionId, minter); cas.setMutability(tokenId, immutable_); cas.pushAssertionId(tokenId, assertionId); @@ -485,7 +505,7 @@ contract ContentAssetV2 is Named, Versioned, HubDependentV2, Initializable { serviceAgreementV1.createServiceAgreement( ServiceAgreementStructsV1.ServiceAgreementInputArgs({ - assetCreator: originalSender, + assetCreator: payer, assetContract: contentAssetStorageAddress, tokenId: tokenId, keyword: abi.encodePacked(contentAssetStorageAddress, assertionId), diff --git a/contracts/v2/paranets/Paranet.sol b/contracts/v2/paranets/Paranet.sol index 4553c0f6..4f37f84a 100644 --- a/contracts/v2/paranets/Paranet.sol +++ b/contracts/v2/paranets/Paranet.sol @@ -67,7 +67,7 @@ contract Paranet is Named, Versioned, ContractStatusV2, Initializable { ); string private constant _NAME = "Paranet"; - string private constant _VERSION = "2.1.3"; + string private constant _VERSION = "2.2.0"; ParanetsRegistry public paranetsRegistry; ParanetServicesRegistry public paranetServicesRegistry; @@ -284,50 +284,16 @@ contract Paranet is Named, Versioned, ContractStatusV2, Initializable { uint256 paranetKATokenId, ContentAssetStructs.AssetInputArgs calldata knowledgeAssetArgs ) external returns (uint256) { - ParanetsRegistry pr = paranetsRegistry; - - // Check if Paranet exists - // If not: Throw an error - if (!pr.paranetExists(keccak256(abi.encodePacked(paranetKAStorageContract, paranetKATokenId)))) { - revert ParanetErrors.ParanetDoesntExist(paranetKAStorageContract, paranetKATokenId); - } - - // Check if Knowledge Miner has profile - // If not: Create a profile - if (!paranetKnowledgeMinersRegistry.knowledgeMinerExists(msg.sender)) { - paranetKnowledgeMinersRegistry.registerKnowledgeMiner(msg.sender); - } - - // Check if Knowledge Miner is registert to paranet - // If not: Register it - if ( - !pr.isKnowledgeMinerRegistered( - keccak256(abi.encodePacked(paranetKAStorageContract, paranetKATokenId)), - msg.sender - ) - ) { - pr.addKnowledgeMiner(keccak256(abi.encodePacked(paranetKAStorageContract, paranetKATokenId)), msg.sender); - } - - // Mint Knowledge Asset - uint256 knowledgeAssetTokenId = contentAsset.createAssetFromContract(msg.sender, knowledgeAssetArgs); - - _updateSubmittedKnowledgeAssetMetadata( - paranetKAStorageContract, - paranetKATokenId, - address(contentAssetStorage), - knowledgeAssetTokenId, - knowledgeAssetArgs.tokenAmount - ); - - emit KnowledgeAssetSubmittedToParanet( - paranetKAStorageContract, - paranetKATokenId, - address(contentAssetStorage), - knowledgeAssetTokenId - ); + return _mintKnowledgeAsset(paranetKAStorageContract, paranetKATokenId, knowledgeAssetArgs, msg.sender); + } - return knowledgeAssetTokenId; + function mintKnowledgeAssetFor( + address paranetKAStorageContract, + uint256 paranetKATokenId, + ContentAssetStructs.AssetInputArgs calldata knowledgeAssetArgs, + address miner + ) external returns (uint256) { + return _mintKnowledgeAsset(paranetKAStorageContract, paranetKATokenId, knowledgeAssetArgs, miner); } function submitKnowledgeAsset( @@ -376,7 +342,7 @@ contract Paranet is Named, Versioned, ContractStatusV2, Initializable { paranetKnowledgeMinersRegistry.registerKnowledgeMiner(msg.sender); } - // Check if Knowledge Miner is registert to paranet + // Check if Knowledge Miner is registered in the paranet // If not: Register it if ( !pr.isKnowledgeMinerRegistered( @@ -392,7 +358,8 @@ contract Paranet is Named, Versioned, ContractStatusV2, Initializable { paranetKATokenId, knowledgeAssetStorageContract, knowledgeAssetTokenId, - remainingTokenAmount + remainingTokenAmount, + msg.sender ); emit KnowledgeAssetSubmittedToParanet( @@ -420,12 +387,66 @@ contract Paranet is Named, Versioned, ContractStatusV2, Initializable { ); } + function _mintKnowledgeAsset( + address paranetKAStorageContract, + uint256 paranetKATokenId, + ContentAssetStructs.AssetInputArgs calldata knowledgeAssetArgs, + address miner + ) internal returns (uint256) { + ParanetsRegistry pr = paranetsRegistry; + + // Check if Paranet exists + // If not: Throw an error + if (!pr.paranetExists(keccak256(abi.encodePacked(paranetKAStorageContract, paranetKATokenId)))) { + revert ParanetErrors.ParanetDoesntExist(paranetKAStorageContract, paranetKATokenId); + } + + // Check if Knowledge Miner has profile + // If not: Create a profile + if (!paranetKnowledgeMinersRegistry.knowledgeMinerExists(miner)) { + paranetKnowledgeMinersRegistry.registerKnowledgeMiner(miner); + } + + // Check if Knowledge Miner is registered in the paranet + // If not: Register it + if ( + !pr.isKnowledgeMinerRegistered( + keccak256(abi.encodePacked(paranetKAStorageContract, paranetKATokenId)), + miner + ) + ) { + pr.addKnowledgeMiner(keccak256(abi.encodePacked(paranetKAStorageContract, paranetKATokenId)), miner); + } + + // Mint Knowledge Asset + uint256 knowledgeAssetTokenId = contentAsset.createAssetFromContract(miner, msg.sender, knowledgeAssetArgs); + + _updateSubmittedKnowledgeAssetMetadata( + paranetKAStorageContract, + paranetKATokenId, + address(contentAssetStorage), + knowledgeAssetTokenId, + knowledgeAssetArgs.tokenAmount, + miner + ); + + emit KnowledgeAssetSubmittedToParanet( + paranetKAStorageContract, + paranetKATokenId, + address(contentAssetStorage), + knowledgeAssetTokenId + ); + + return knowledgeAssetTokenId; + } + function _updateSubmittedKnowledgeAssetMetadata( address paranetKAStorageContract, uint256 paranetKATokenId, address knowledgeAssetStorageContract, uint256 knowledgeAssetTokenId, - uint96 tokenAmount + uint96 tokenAmount, + address miner ) internal { ParanetsRegistry pr = paranetsRegistry; ParanetKnowledgeMinersRegistry pkmr = paranetKnowledgeMinersRegistry; @@ -435,7 +456,7 @@ contract Paranet is Named, Versioned, ContractStatusV2, Initializable { keccak256(abi.encodePacked(paranetKAStorageContract, paranetKATokenId)), knowledgeAssetStorageContract, knowledgeAssetTokenId, - msg.sender + miner ); // Add Knowledge Asset Metadata to the ParanetsRegistry @@ -450,22 +471,22 @@ contract Paranet is Named, Versioned, ContractStatusV2, Initializable { // Add Knowledge Asset Metadata to the KnowledgeMinersRegistry pkmr.addSubmittedKnowledgeAsset( - msg.sender, + miner, keccak256(abi.encodePacked(paranetKAStorageContract, paranetKATokenId)), keccak256(abi.encodePacked(knowledgeAssetStorageContract, knowledgeAssetTokenId)) ); pkmr.addCumulativeTracSpent( - msg.sender, + miner, keccak256(abi.encodePacked(paranetKAStorageContract, paranetKATokenId)), tokenAmount ); pkmr.addUnrewardedTracSpent( - msg.sender, + miner, keccak256(abi.encodePacked(paranetKAStorageContract, paranetKATokenId)), tokenAmount ); - pkmr.incrementTotalSubmittedKnowledgeAssetsCount(msg.sender); - pkmr.addTotalTracSpent(msg.sender, tokenAmount); + pkmr.incrementTotalSubmittedKnowledgeAssetsCount(miner); + pkmr.addTotalTracSpent(miner, tokenAmount); } function _processUpdatedKnowledgeAssetStatesMetadata( diff --git a/package-lock.json b/package-lock.json index b98311ca..bb1c0faf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "dkg-evm-module", - "version": "4.3.3", + "version": "4.3.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "dkg-evm-module", - "version": "4.3.3", + "version": "4.3.4", "license": "Apache-2.0", "dependencies": { "@openzeppelin/contracts": "^4.9.3", diff --git a/package.json b/package.json index c61b4a1f..0a601ff9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dkg-evm-module", - "version": "4.3.3", + "version": "4.3.4", "description": "Smart contracts for OriginTrail V6", "main": "index.ts", "files": [ diff --git a/test/v2/unit/Paranet.test.ts b/test/v2/unit/Paranet.test.ts index 9a2b8b4d..4afcd846 100644 --- a/test/v2/unit/Paranet.test.ts +++ b/test/v2/unit/Paranet.test.ts @@ -127,8 +127,8 @@ describe('@v2 @unit ParanetKnowledgeMinersRegistry contract', function () { expect(await Paranet.name()).to.equal('Paranet'); }); - it('The contract is version "2.1.3"', async () => { - expect(await Paranet.version()).to.equal('2.1.3'); + it('The contract is version "2.2.0"', async () => { + expect(await Paranet.version()).to.equal('2.2.0'); }); it('should register paranet', async () => { @@ -925,6 +925,92 @@ describe('@v2 @unit ParanetKnowledgeMinersRegistry contract', function () { .and.to.emit(ServiceAgreementV1, 'ServiceAgreementV1Created'); }); + it('should mint knowledge asset for miner & add it to paranet', async () => { + await Token.connect(accounts[0]).increaseAllowance(ServiceAgreementV1.address, hre.ethers.utils.parseEther('105')); + const { paranetKAStorageContract, paranetKATokenId, paranetId } = await registerParanet(accounts, Paranet, 3); + const assetInputArgs = { + assertionId: getHashFromNumber(500), + size: 3, + triplesNumber: 1, + chunksNumber: 1, + epochsNumber: 5, + tokenAmount: hre.ethers.utils.parseEther('105'), + scoreFunctionId: 2, + immutable_: false, + }; + + const tx = await Paranet.connect(accounts[0]).mintKnowledgeAssetFor( + paranetKAStorageContract, + paranetKATokenId, + assetInputArgs, + accounts[5].address, + ); + const receipt = await tx.wait(); + const tokenId = Number(receipt.logs[0].topics[3]); + + expect(await ContentAssetStorageV2.ownerOf(tokenId)).to.be.equal(accounts[5].address); + + const knowledgeMinerMetadata = await ParanetKnowledgeMinersRegistry.getKnowledgeMinerMetadata(accounts[5].address); + + expect(knowledgeMinerMetadata.addr).to.be.equal(accounts[5].address); + expect(knowledgeMinerMetadata.totalTracSpent).to.be.equal(hre.ethers.utils.parseEther('105')); + expect(knowledgeMinerMetadata.totalSubmittedKnowledgeAssetsCount).to.be.equal(1); + + const submittedKnowledgeAsset = await ParanetKnowledgeMinersRegistry[ + 'getSubmittedKnowledgeAssets(address,bytes32)' + ](accounts[5].address, paranetId); + + expect(submittedKnowledgeAsset.length).to.be.equal(1); + expect(submittedKnowledgeAsset[0]).to.be.equal(getknowledgeAssetId(ContentAssetStorageV2.address, tokenId)); + + const cumulativeTracSpent = await ParanetKnowledgeMinersRegistry.getCumulativeTracSpent( + accounts[5].address, + paranetId, + ); + + expect(cumulativeTracSpent).to.be.equal(hre.ethers.utils.parseEther('105')); + + const unrewardedTracSpent = await ParanetKnowledgeMinersRegistry.getUnrewardedTracSpent( + accounts[5].address, + paranetId, + ); + + expect(unrewardedTracSpent).to.be.equal(hre.ethers.utils.parseEther('105')); + + const knowledgeAssets = await ParanetsRegistry.getKnowledgeAssets(paranetId); + + expect(knowledgeAssets.length).to.be.equal(1); + expect(knowledgeAssets[0]).to.be.equal(getknowledgeAssetId(ContentAssetStorageV2.address, tokenId)); + + const cumulativeKnowledgeValue = await ParanetsRegistry.getCumulativeKnowledgeValue(paranetId); + + expect(cumulativeKnowledgeValue).to.be.equal(hre.ethers.utils.parseEther('105')); + + const isKnowledgeAssetRegistered = await ParanetsRegistry.isKnowledgeAssetRegistered( + paranetId, + getknowledgeAssetId(ContentAssetStorageV2.address, tokenId), + ); + + expect(isKnowledgeAssetRegistered).to.be.equal(true); + + const knowledgeAssetsCount = await ParanetsRegistry.getKnowledgeAssetsCount(paranetId); + + expect(knowledgeAssetsCount).to.be.equal(1); + + const isKnowledgeMinerRegistered = await ParanetsRegistry.isKnowledgeMinerRegistered( + paranetId, + accounts[5].address, + ); + + expect(isKnowledgeMinerRegistered).to.be.equal(true); + + expect( + await ParanetKnowledgeAssetsRegistry.isParanetKnowledgeAsset( + getknowledgeAssetId(ContentAssetStorageV2.address, tokenId), + ), + ).to.be.equal(true); + }); + async function registerParanet(accounts: SignerWithAddress[], Paranet: Paranet, number: number) { const assetInputArgs = { assertionId: getHashFromNumber(number),