-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
3078 - Series indexer contract #44
base: main
Are you sure you want to change the base?
Conversation
Implement version 1 Better naming f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit
solhint
GC: Use Custom Errors instead of require statements
require(proposedArtistAddr != address(0), "Invalid address"); |
GC: Use Custom Errors instead of require statements
require(!seriesPendingCoArtist[seriesID][proposedArtistID], "Already proposed"); |
GC: Use Custom Errors instead of require statements
require(seriesPendingCoArtist[seriesID][proposedArtistID], "No proposal exists"); |
GC: Use Custom Errors instead of require statements
require(artistID != 0, "Not an artist"); |
GC: Use Custom Errors instead of require statements
require(seriesPendingCoArtist[seriesID][artistID], "No pending proposal"); |
GC: Use Custom Errors instead of require statements
require(artistID != 0, "Not an artist"); |
GC: Use Custom Errors instead of require statements
require(!ownerRightsRevokedForArtistID[artistID], "Already revoked"); |
GC: Use Custom Errors instead of require statements
require(artistID != 0, "Not an artist"); |
GC: Use Custom Errors instead of require statements
require(ownerRightsRevokedForArtistID[artistID], "Not revoked"); |
GC: Use Custom Errors instead of require statements
require(newAddress != address(0), "Invalid new address"); |
Error message for require is too long: 37 counted / 32 allowed
require(addressToArtistID[newAddress] == 0, "Address already assigned to an artist"); |
GC: String exceeds 32 bytes
require(addressToArtistID[newAddress] == 0, "Address already assigned to an artist"); |
GC: Use Custom Errors instead of require statements
require(addressToArtistID[newAddress] == 0, "Address already assigned to an artist"); |
GC: Use Custom Errors instead of require statements
require(oldAddress != address(0), "Invalid artistID"); |
GC: Use Custom Errors instead of require statements
require(isCallerArtist || isOwnerWithRights, "Not authorized to update address"); |
Error message for revert is too long: 39 counted / 32 allowed
revert("One of the artists revoked owner rights"); |
GC: String exceeds 32 bytes
revert("One of the artists revoked owner rights"); |
GC: Use Custom Errors instead of revert statements
revert("One of the artists revoked owner rights"); |
a8851ad
to
abf3af4
Compare
contracts/SeriesIndexer.sol
Outdated
|
||
contract SeriesIndexer is Ownable.Ownable { | ||
// Counter | ||
uint256 private nextSeriesID = 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use the length
of existing series map so we don't need to maintain this counter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this's not possible since the mapping in solidity is a simple hash table without key management.
contracts/SeriesIndexer.sol
Outdated
contract SeriesIndexer is Ownable.Ownable { | ||
// Counter | ||
uint256 private nextSeriesID = 1; | ||
uint256 private nextArtistID = 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same has above comment but for the artist map.
contracts/SeriesIndexer.sol
Outdated
uint256 private nextArtistID = 1; | ||
|
||
struct Series { | ||
string metadata; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose this field is for series metadata source, so it should store the uri so the name should be metadataURI
contracts/SeriesIndexer.sol
Outdated
|
||
struct Series { | ||
string metadata; | ||
string contractTokenData; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above comment, it should be tokenDataURI
contracts/SeriesIndexer.sol
Outdated
// Artist Management | ||
mapping(uint256 => address) private artistIDToAddress; | ||
mapping(address => uint256) private addressToArtistID; | ||
mapping(uint256 => bool) private ownerRightsRevokedForArtistID; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be on series level instead of artist level. We could also provide a feature for revoking all series from an artist.
contracts/SeriesIndexer.sol
Outdated
// Internal Helper Functions | ||
// ------------------------ | ||
|
||
function _checkOwnerOrArtist(uint256 seriesID) internal view { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should pass the address instead of assume the msg.sender
. The caller should determine which one should be passed, that will be more extensible and readable. If we just want to stick with the msg.sender
, we might need a better name like _checkMsgSenderIsOwnerOrArtist
contracts/SeriesIndexer.sol
Outdated
} | ||
} | ||
|
||
function _checkArtist(uint256 seriesID) internal view { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same here.
contracts/SeriesIndexer.sol
Outdated
uint256 indexed seriesID, | ||
uint256[] artistIDs, | ||
string metadata, | ||
string seriesContractTokenCID |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer using something like URI
instead of CID
that we need to stick to ipfs. Using URI
could be better for extensibility later on.
contracts/SeriesIndexer.sol
Outdated
require(length <= 50, "Batch size too large"); // Prevent DOS attacks | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this mean for prevent DOS attacks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that mean if someone try to put really large number of list, the contract will deny to service. It's not quite of an attack I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the words is removed anyway
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So that could be out of gas since it could reach the block gas limit so i don't consider it as "denial of service"
contracts/SeriesIndexer.sol
Outdated
seriesExists(seriesID) | ||
onlyOwnerOrArtist(seriesID) | ||
{ | ||
Series storage series = seriesDetails[seriesID]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should use memory
contracts/SeriesIndexer.sol
Outdated
Series storage series = seriesDetails[seriesID]; | ||
for (uint256 i = 0; i < series.artistIDs.length; i++) { | ||
uint256 artistID = series.artistIDs[i]; | ||
isArtistIDInSeries[seriesID][artistID] = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be redundant since we did it in the _removeSeriesFromArtist
for (uint256 i = 0; i < series.artistIDs.length; i++) { | ||
uint256 artistID = series.artistIDs[i]; | ||
isArtistIDInSeries[seriesID][artistID] = false; | ||
_removeSeriesFromArtist(artistID, seriesID); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't we call the function _removeArtistFromSeries
as well if we tend to remove the artist from series?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nvm, you did it when deleting the storage below.
|
||
_ensureArtistHasID(proposedArtistAddr); | ||
uint256 proposedArtistID = addressToArtistID[proposedArtistAddr]; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like you don't check the proposed address has been already artist for this series.
contracts/SeriesIndexer.sol
Outdated
} | ||
|
||
Series storage series = seriesDetails[seriesID]; | ||
series.artistIDs.push(artistID); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic could be presented already in _addArtistsToSeries
, could it be reused?
contracts/SeriesIndexer.sol
Outdated
if (artistID == 0) { | ||
revert NotAnArtistError(msg.sender); | ||
} | ||
if (!ownerRightsRevokedForArtistID[artistID]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Redundant parentheses
pragma solidity ^0.8.0; | ||
|
||
import "@openzeppelin/contracts/access/Ownable.sol" as Ownable; | ||
import "@openzeppelin/contracts/utils/structs/BitMaps.sol"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
global import of path @openzeppelin/contracts/utils/structs/BitMaps.sol is not allowed. Specify names to import individually or bind all exports of the module into a name (import "path" as Name)
7591cdd
to
ca84544
Compare
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import "@openzeppelin/contracts/access/Ownable.sol"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
global import of path @openzeppelin/contracts/access/Ownable.sol is not allowed. Specify names to import individually or bind all exports of the module into a name (import "path" as Name)
Description
Document of the flow design and/or figma design