Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 32 additions & 6 deletions contracts/contribution/ContributionNft.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,14 @@ contract ContributionNft is
mapping(uint256 => uint8) private _cores;

mapping(uint256 => bool) public modelContributions;
mapping(uint256 => uint256) public modelDatasets;

event NewContribution(uint256 tokenId, uint256 virtualId, uint256 parentId);
event NewContribution(
uint256 tokenId,
uint256 virtualId,
uint256 parentId,
uint256 datasetId
);

address private _admin; // Admin is able to create contribution proposal without votes

Expand Down Expand Up @@ -59,7 +65,8 @@ contract ContributionNft is
string memory newTokenURI,
uint256 proposalId,
uint256 parentId,
bool isModel_
bool isModel_,
uint256 datasetId
) external returns (uint256) {
IGovernor personaDAO = getAgentDAO(virtualId);
require(
Expand All @@ -77,9 +84,10 @@ contract ContributionNft is

if (isModel_) {
modelContributions[proposalId] = true;
modelDatasets[proposalId] = datasetId;
}

emit NewContribution(proposalId, virtualId, parentId);
emit NewContribution(proposalId, virtualId, parentId, datasetId);

return proposalId;
}
Expand All @@ -100,7 +108,11 @@ contract ContributionNft is
)
public
view
override(IContributionNft, ERC721Upgradeable, ERC721URIStorageUpgradeable)
override(
IContributionNft,
ERC721Upgradeable,
ERC721URIStorageUpgradeable
)
returns (string memory)
{
return super.tokenURI(tokenId);
Expand All @@ -125,7 +137,11 @@ contract ContributionNft is
)
public
view
override(ERC721Upgradeable, ERC721URIStorageUpgradeable, ERC721EnumerableUpgradeable)
override(
ERC721Upgradeable,
ERC721URIStorageUpgradeable,
ERC721EnumerableUpgradeable
)
returns (bool)
{
return super.supportsInterface(interfaceId);
Expand All @@ -142,7 +158,11 @@ contract ContributionNft is
address to,
uint256 tokenId,
address auth
) internal override(ERC721Upgradeable, ERC721EnumerableUpgradeable) returns (address) {
)
internal
override(ERC721Upgradeable, ERC721EnumerableUpgradeable)
returns (address)
{
return super._update(to, tokenId, auth);
}

Expand All @@ -155,4 +175,10 @@ contract ContributionNft is
) public view override(IERC721, ERC721Upgradeable) returns (address) {
return _ownerOf(tokenId);
}

function getDatasetId(
uint256 tokenId
) external view returns (uint256) {
return modelDatasets[tokenId];
}
}
1 change: 1 addition & 0 deletions contracts/contribution/IContributionNft.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ interface IContributionNft {
function getCore(uint256 tokenId) external view returns (uint8);
function isModel(uint256 tokenId) external view returns (bool);
function getAdmin() external view returns (address);
function getDatasetId(uint256 tokenId) external view returns (uint256);
}
29 changes: 21 additions & 8 deletions contracts/contribution/IServiceNft.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,18 @@
pragma solidity ^0.8.20;

interface IServiceNft {

function getCore(uint256 tokenId) external view returns (uint8);

function getMaturity(uint256 tokenId) external view returns (uint16);
function getMaturity(uint256 tokenId) external view returns (uint256);

function getImpact(uint256 tokenId) external view returns (uint16);
function getImpact(uint256 tokenId) external view returns (uint256);

function getCoreService(
uint256 virtualId,
uint8 coreType
) external view returns (uint256);

event CoreServiceUpdated(
uint256 virtualId,
uint8 coreType,
uint256 serviceId
);

function getCoreDatasetAt(
uint256 virtualId,
uint8 coreType,
Expand All @@ -36,4 +31,22 @@ interface IServiceNft {
) external view returns (uint256[] memory);

function getMintedAt(uint256 tokenId) external view returns (uint256);

event CoreServiceUpdated(
uint256 virtualId,
uint8 coreType,
uint256 serviceId
);

event NewService(
uint256 tokenId,
uint8 coreId,
uint256 maturity,
uint256 impact,
bool isModel
);

event DatasetImpactUpdated(uint16 weight);

event SetServiceScore(uint256 serviceId, uint256 eloRating, uint256 impact);
}
83 changes: 56 additions & 27 deletions contracts/contribution/ServiceNft.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts/interfaces/IERC5805.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "../virtualPersona/IAgentNft.sol";
Expand All @@ -19,31 +19,26 @@ contract ServiceNft is
Initializable,
ERC721Upgradeable,
ERC721EnumerableUpgradeable,
ERC721URIStorageUpgradeable
ERC721URIStorageUpgradeable,
OwnableUpgradeable
{
uint256 private _nextTokenId;

address public personaNft;
address public contributionNft;

uint16 public datasetImpactWeight;

mapping(uint256 tokenId => uint8 coreId) private _cores;
mapping(uint256 tokenId => uint16 maturity) private _maturities;
mapping(uint256 tokenId => uint16 impact) private _impacts;
mapping(uint256 tokenId => uint256 maturity) private _maturities;
mapping(uint256 tokenId => uint256 impact) private _impacts;
mapping(uint256 tokenId => uint256 blockNumber) private _mintedAts;

mapping(uint256 personaId => mapping(uint8 coreId => uint256 serviceId))
private _coreServices; // Latest service NFT id for a core
mapping(uint256 personaId => mapping(uint8 coreId => uint256[] serviceId))
private _coreDatasets;

event NewService(
uint256 tokenId,
uint8 coreId,
uint16 maturity,
uint16 impact,
bool isModel
);

function initialize(
address initialAgentNft,
address initialContributionNft
Expand All @@ -57,8 +52,9 @@ contract ServiceNft is
uint256 virtualId,
bytes32 descHash
) external returns (uint256) {
IAgentNft.VirtualInfo memory info = IAgentNft(personaNft)
.virtualInfo(virtualId);
IAgentNft.VirtualInfo memory info = IAgentNft(personaNft).virtualInfo(
virtualId
);
require(_msgSender() == info.dao, "Caller is not VIRTUAL DAO");

IGovernor personaDAO = IGovernor(info.dao);
Expand All @@ -85,20 +81,14 @@ contract ServiceNft is
);
// Calculate maturity
_maturities[proposalId] = IAgentDAO(info.dao).getMaturity(proposalId);
// Calculate impact
// Get current service maturity
uint256 prevServiceId = _coreServices[virtualId][_cores[proposalId]];

_impacts[proposalId] = _maturities[proposalId] >
_maturities[prevServiceId]
? _maturities[proposalId] - _maturities[prevServiceId]
: 0;

bool isModel = IContributionNft(contributionNft).isModel(proposalId);

if (isModel) {
_coreServices[virtualId][_cores[proposalId]] = proposalId;
emit CoreServiceUpdated(virtualId, _cores[proposalId], proposalId);

updateImpact(virtualId, proposalId);
} else {
_coreDatasets[virtualId][_cores[proposalId]].push(proposalId);
}
Expand All @@ -114,17 +104,38 @@ contract ServiceNft is
return proposalId;
}

function updateImpact(uint256 virtualId, uint256 proposalId) public {
// Calculate impact
// Get current service maturity
uint256 prevServiceId = _coreServices[virtualId][_cores[proposalId]];
uint256 rawImpact = _maturities[proposalId] > _maturities[prevServiceId]
? _maturities[proposalId] - _maturities[prevServiceId]
: 0;
uint256 datasetId = IContributionNft(contributionNft).getDatasetId(
proposalId
);

_impacts[proposalId] = rawImpact;
if (datasetId > 0) {
_impacts[datasetId] = (rawImpact * datasetImpactWeight) / 10000;
_impacts[proposalId] = rawImpact - _impacts[datasetId];

emit SetServiceScore(proposalId, _maturities[proposalId], _impacts[proposalId]);
emit SetServiceScore(datasetId, _maturities[proposalId], _impacts[datasetId]);
}
}

function getCore(uint256 tokenId) public view returns (uint8) {
_requireOwned(tokenId);
return _cores[tokenId];
}

function getMaturity(uint256 tokenId) public view returns (uint16) {
function getMaturity(uint256 tokenId) public view returns (uint256) {
_requireOwned(tokenId);
return _maturities[tokenId];
}

function getImpact(uint256 tokenId) public view returns (uint16) {
function getImpact(uint256 tokenId) public view returns (uint256) {
_requireOwned(tokenId);
return _impacts[tokenId];
}
Expand Down Expand Up @@ -163,11 +174,21 @@ contract ServiceNft is
return _coreDatasets[virtualId][coreType];
}

function setDatasetImpactWeight(uint16 weight) public onlyOwner {
datasetImpactWeight = weight;
emit DatasetImpactUpdated(weight);
}

// The following functions are overrides required by Solidity.

function tokenURI(
uint256 tokenId
) public view override(ERC721Upgradeable, ERC721URIStorageUpgradeable) returns (string memory) {
)
public
view
override(ERC721Upgradeable, ERC721URIStorageUpgradeable)
returns (string memory)
{
// Service NFT is a mirror of Contribution NFT
return IContributionNft(contributionNft).tokenURI(tokenId);
}
Expand All @@ -177,7 +198,11 @@ contract ServiceNft is
)
public
view
override(ERC721Upgradeable, ERC721URIStorageUpgradeable, ERC721EnumerableUpgradeable)
override(
ERC721Upgradeable,
ERC721URIStorageUpgradeable,
ERC721EnumerableUpgradeable
)
returns (bool)
{
return super.supportsInterface(interfaceId);
Expand All @@ -194,7 +219,11 @@ contract ServiceNft is
address to,
uint256 tokenId,
address auth
) internal override(ERC721Upgradeable, ERC721EnumerableUpgradeable) returns (address) {
)
internal
override(ERC721Upgradeable, ERC721EnumerableUpgradeable)
returns (address)
{
return super._update(to, tokenId, auth);
}
}
9 changes: 3 additions & 6 deletions contracts/virtualPersona/AgentDAO.sol
Original file line number Diff line number Diff line change
Expand Up @@ -200,15 +200,12 @@ contract AgentDAO is

_proposalMaturities[proposalId] += (maturity * weight);

emit NewEloRating(proposalId, account, maturity, votes);
emit ValidatorEloRating(proposalId, account, maturity, votes);
}

function getMaturity(uint256 proposalId) public view returns (uint16) {
function getMaturity(uint256 proposalId) public view returns (uint256) {
(, uint256 forVotes, ) = proposalVotes(proposalId);
return
SafeCast.toUint16(
Math.min(10000, _proposalMaturities[proposalId] / forVotes)
);
return Math.min(10000, _proposalMaturities[proposalId] / forVotes);
}

function quorum(
Expand Down
4 changes: 2 additions & 2 deletions contracts/virtualPersona/IAgentDAO.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ interface IAgentDAO {
uint256 timepoint
) external view returns (uint256);

function getMaturity(uint256 proposalId) external view returns (uint16);
function getMaturity(uint256 proposalId) external view returns (uint256);

event NewEloRating(uint256 proposalId, address voter, uint256 score, uint8[] votes);
event ValidatorEloRating(uint256 proposalId, address voter, uint256 score, uint8[] votes);
}