This report was generated by Aderyn, a static analysis tool built by Cyfrin, a blockchain security company. This report is not a substitute for manual audit or security review. It should not be relied upon for any purpose other than to assist in the identification of potential security vulnerabilities.
- Summary
- High Issues
- Low Issues
- L-1: Centralization Risk for trusted owners
- L-2: Unsafe ERC20 Operations should not be used
- L-3: Solidity pragma should be specific, not wide
- L-4: Missing checks for
address(0)
when assigning values to address state variables - L-5:
public
functions not used internally could be markedexternal
- L-6: Define and use
constant
variables instead of using literals - L-7: PUSH0 is not supported by all chains
- L-8: Modifiers invoked only once can be shoe-horned into the function
- L-9: Internal functions called only once can be inlined
- L-10: Unused Custom Error
Key | Value |
---|---|
.sol Files | 6 |
Total nSLOC | 768 |
Filepath | nSLOC |
---|---|
src/ARTBlockVoting.sol | 77 |
src/ArtBlockAMM.sol | 81 |
src/ArtBlockGovernance.sol | 148 |
src/ArtBlockNFT.sol | 47 |
src/CustomERC20Token.sol | 26 |
src/MainEngine.sol | 389 |
Total | 768 |
Category | No. of Issues |
---|---|
High | 5 |
Low | 10 |
Passing an arbitrary from
address to transferFrom
(or safeTransferFrom
) can lead to loss of funds, because anyone can transfer tokens from the from
address if an approval is made.
2 Found Instances
Consider protecting the initializer functions with modifiers.
2 Found Instances
When compiling contracts with certain development frameworks (for example: Truffle), having contracts with the same name across different files can lead to one being overwritten.
2 Found Instances
Solidity does initialize variables by default when you declare them, however it's good practice to explicitly declare an initial value. For example, if you transfer money to an address we must make sure that the address has been initialized.
1 Found Instances
-
Found in src/ArtBlockNFT.sol Line: 11
uint256 private _nextTokenId;
The use of keccak256 hash functions on predictable values like block.timestamp, block.number, or similar data, including modulo operations on these values, should be avoided for generating randomness, as they are easily predictable and manipulable. The PREVRANDAO
opcode also should not be used as a source of randomness. Instead, utilize Chainlink VRF for cryptographically secure and provably random values to ensure protocol integrity.
1 Found Instances
-
Found in src/MainEngine.sol Line: 340
bytes4 productId = bytes4(keccak256(abi.encodePacked(msg.sender, block.timestamp, metadata, price, commToken)));
Contracts have owners with privileged rights to perform admin tasks and need to be trusted to not perform malicious updates or drain funds.
4 Found Instances
-
Found in src/ArtBlockNFT.sol Line: 10
contract ArtBlockNFT is ERC721, ERC721Enumerable, ERC721URIStorage, Ownable {
-
Found in src/ArtBlockNFT.sol Line: 17
function safeMint(address to, string memory uri, bytes4 productId) external onlyOwner {
-
Found in src/ArtBlockNFT.sol Line: 24
function safeTransfer(address from, address to, uint256 tokenId) external onlyOwner {
-
Found in src/CustomERC20Token.sol Line: 13
contract CustomERC20Token is ERC20, ERC20Burnable, Ownable {
ERC20 functions may not behave as expected. For example: return values are not always meaningful. It is recommended to use OpenZeppelin's SafeERC20 library.
15 Found Instances
-
Found in src/ArtBlockAMM.sol Line: 47
tokenIn.transferFrom(msg.sender, address(this), _amountIn);
-
Found in src/ArtBlockAMM.sol Line: 53
tokenOut.transfer(msg.sender, amountOut);
-
Found in src/ArtBlockAMM.sol Line: 59
token0.transferFrom(msg.sender, address(this), _amount0);
-
Found in src/ArtBlockAMM.sol Line: 60
token1.transferFrom(msg.sender, address(this), _amount1);
-
Found in src/ArtBlockAMM.sol Line: 88
token0.transfer(msg.sender, amount0);
-
Found in src/ArtBlockAMM.sol Line: 89
token1.transfer(msg.sender, amount1);
-
Found in src/MainEngine.sol Line: 256
artBlockToken.transferFrom(communityCreator, address(this), COMMUNITY_CREATION_FEE * PRECESSION);
-
Found in src/MainEngine.sol Line: 320
artBlockToken.transferFrom(to, address(this), cost * PRECESSION);
-
Found in src/MainEngine.sol Line: 352
CustomERC20Token(commToken).transferFrom(msg.sender, address(this), stakedAmount);
-
Found in src/MainEngine.sol Line: 409
CustomERC20Token(productInfo[productId].currentCommunity).transfer(
-
Found in src/MainEngine.sol Line: 420
CustomERC20Token(productInfo[productId].currentCommunity).transfer(
-
Found in src/MainEngine.sol Line: 478
CustomERC20Token(communityToken).transferFrom(msg.sender, product.author, (product.price * 3) / 100);
-
Found in src/MainEngine.sol Line: 479
CustomERC20Token(communityToken).transferFrom(
-
Found in src/MainEngine.sol Line: 483
CustomERC20Token(communityToken).transferFrom(msg.sender, product.currentOwner, product.price);
-
Found in src/MainEngine.sol Line: 523
CustomERC20Token(community).transfer(communityInfo[community].communityCreator, (price * 3) / 100);
Consider using a specific version of Solidity in your contracts instead of a wide version. For example, instead of pragma solidity ^0.8.0;
, use pragma solidity 0.8.0;
6 Found Instances
-
Found in src/ARTBlockVoting.sol Line: 24
pragma solidity ^0.8.20;
-
Found in src/ArtBlockAMM.sol Line: 2
pragma solidity ^0.8.24;
-
Found in src/ArtBlockGovernance.sol Line: 2
pragma solidity ^0.8.20;
-
Found in src/ArtBlockNFT.sol Line: 3
pragma solidity ^0.8.20;
-
Found in src/CustomERC20Token.sol Line: 2
pragma solidity ^0.8.20;
-
Found in src/MainEngine.sol Line: 24
pragma solidity ^0.8.23;
Check for address(0)
when assigning values to address state variables.
3 Found Instances
Instead of marking a function as public
, consider marking it as external
if it is not used internally.
16 Found Instances
-
Found in src/ArtBlockNFT.sol Line: 50
function tokenURI(uint256 tokenId) public view override(ERC721, ERC721URIStorage) returns (string memory) {
-
Found in src/ArtBlockNFT.sol Line: 54
function supportsInterface(bytes4 interfaceId)
-
Found in src/CustomERC20Token.sol Line: 68
function mint(address to, uint256 amount) public onlyMainEngine {
-
Found in src/CustomERC20Token.sol Line: 79
function burnFrom(address account, uint256 amount) public override onlyMainEngine {
-
Found in src/CustomERC20Token.sol Line: 88
function decimals() public view virtual override returns (uint8) {
-
Found in src/MainEngine.sol Line: 290
function buyArtBlockToken(address to, uint256 amount) public payable {
-
Found in src/MainEngine.sol Line: 314
function buyCommunityToken(address to, uint256 amount, address communityToken) public {
-
Found in src/MainEngine.sol Line: 430
function canCalculateVotingResult(bytes4 productId) public view returns (bool) {
-
Found in src/MainEngine.sol Line: 441
function listProductToMarketPlace(
-
Found in src/MainEngine.sol Line: 466
function buyProduct(
-
Found in src/MainEngine.sol Line: 614
function getTokenAddress() public view returns (address) {
-
Found in src/MainEngine.sol Line: 622
function getCreatorProtocol() public view returns (address) {
-
Found in src/MainEngine.sol Line: 632
function isCommunityMembr(address user, address communityToken) public view returns (bool) {
-
Found in src/MainEngine.sol Line: 646
function getTotalMemberOfCommunity(address communityToken) public view returns (uint256) {
-
Found in src/MainEngine.sol Line: 654
function getCommunityActivityPoints(address communityToken) public view returns (uint256) {
-
Found in src/MainEngine.sol Line: 658
function getCommunityCreationFee() public pure returns (uint256) {
If the same constant literal value is used multiple times, create a constant state variable and reference it throughout the contract.
20 Found Instances
-
Found in src/ARTBlockVoting.sol Line: 150
uint256 communityTokenWeight = (userCommunitytoken * 6) / 10; // 60% weightage of the
-
Found in src/ARTBlockVoting.sol Line: 152
uint256 artblockTokenWeight = (userArtBlockToken * 4) / 10; // 40% weightage of the artblock
-
Found in src/ArtBlockGovernance.sol Line: 228
uint256 communityTokenWeight = (userCommunitytoken * 6) / 10; // 60% weightage of the community token
-
Found in src/ArtBlockGovernance.sol Line: 229
uint256 artblockTokenWeight = (userArtBlockToken * 4) / 10; // 40% weightage of the artblock token
-
Found in src/MainEngine.sol Line: 419
uint256 halfStakeValue = (productBaseInfo[productId].stakeAmount * 50) / 100;
-
Found in src/MainEngine.sol Line: 478
CustomERC20Token(communityToken).transferFrom(msg.sender, product.author, (product.price * 3) / 100);
-
Found in src/MainEngine.sol Line: 480
msg.sender, product.currentOwner, (product.price * 97) / 100
-
Found in src/MainEngine.sol Line: 517
if (getUserActivityPoints(msg.sender, community) < 10) {
-
Found in src/MainEngine.sol Line: 523
CustomERC20Token(community).transfer(communityInfo[community].communityCreator, (price * 3) / 100);
-
Found in src/MainEngine.sol Line: 543
return (price * 3 * PRECESSION) / 10; // If the product is exclusive then the stake amount is 30% of the
-
Found in src/MainEngine.sol Line: 546
return (price * 15 * PRECESSION) / 100; // If the product is not exclusive then the stake amount is 15% of
-
Found in src/MainEngine.sol Line: 568
uint256 rateIncrease = (communityPoints * 1000) / 1000; // Example: rate increases by 1% for every 1000 points
-
Found in src/MainEngine.sol Line: 569
uint256 userDiscount = (userPoints * 100) / 100; // Example: 1% discount for every 100 points
-
Found in src/MainEngine.sol Line: 570
uint256 adjustment = 1 ether + (rateIncrease * 1 ether / 100) - (userDiscount * 1 ether / 100);
Solc compiler version 0.8.20 switches the default target EVM version to Shanghai, which means that the generated bytecode will include PUSH0 opcodes. Be sure to select the appropriate EVM version in case you intend to deploy on a chain other than mainnet like L2 chains that may not support PUSH0, otherwise deployment of your contracts will fail.
6 Found Instances
-
Found in src/ARTBlockVoting.sol Line: 24
pragma solidity ^0.8.20;
-
Found in src/ArtBlockAMM.sol Line: 2
pragma solidity ^0.8.24;
-
Found in src/ArtBlockGovernance.sol Line: 2
pragma solidity ^0.8.20;
-
Found in src/ArtBlockNFT.sol Line: 3
pragma solidity ^0.8.20;
-
Found in src/CustomERC20Token.sol Line: 2
pragma solidity ^0.8.20;
-
Found in src/MainEngine.sol Line: 24
pragma solidity ^0.8.23;
5 Found Instances
-
Found in src/ARTBlockVoting.sol Line: 77
modifier onlyMainEngine() {
-
Found in src/ArtBlockGovernance.sol Line: 71
modifier onlyMainEngine() {
-
Found in src/ArtBlockGovernance.sol Line: 78
modifier onlyCommunityMember(address communityToken) {
-
Found in src/MainEngine.sol Line: 197
modifier hasEnoughBalanceToBuy(bytes4 productId, address communityToken) {
-
Found in src/MainEngine.sol Line: 204
modifier canPostProductToSell(bytes4 productId) {
Instead of separating the logic into a separate function, consider inlining the logic into the calling function. This can reduce the number of function calls and improve readability.
3 Found Instances
-
Found in src/ArtBlockGovernance.sol Line: 202
function initializeRateChangeProposal(
-
Found in src/MainEngine.sol Line: 541
function getStackAmountFromPrice(uint256 price, bool isExclusive) internal view returns (uint256) {
-
Found in src/MainEngine.sol Line: 567
function calculateRateAdjustment(uint256 communityPoints, uint256 userPoints) internal pure returns (uint256) {
it is recommended that the definition be removed when custom error is unused
1 Found Instances
-
Found in src/MainEngine.sol Line: 58
error MainEngine__ProductAlreadyExists();