3

Isn't it possible to define modifiers in libraries? I'm really asking myself why, because thats some functionality you would need over and over again.

If I would like to hypothetically implement some ownable modifier and let that be used in many of my contracts, I would have to implement it in every of my contracts or use another contract (no library), that provides the modifier.

I've seen https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/ownership/Ownable.sol and they implement the functionality also as a contract rather than a function as, I guess, modifiers cannot be accessed from Solidity libraries?

My question: should I now implement my modifiers in my abstract contracts or define modifiers in a contract on its own like the Zeppelin guys did? Whats the up/downsides?

2 Answers 2

10

Library may define and use modifiers, but it cannot export them. Modifiers are compile-time feature, kind of macros. Modifier code is substituted by compiler to every method that uses this modifier. For complex modifiers this may be a problem, but you may always move modifier's logic into a function (library function, probably), and then refer to this function from within modifier. You may also implement common modifiers in interface to share them among several contracts:

library Foo {
    modifier nonZero (uint x) {
        require (x != 0);
        _;
    }

    function isPrime (uint x) public nonZero (x) returns (bool) {
        // Complicated logic here
    }
}

interface Bar {
    modifier onlyPrime (uint x) {
        require (Foo.isPrime (x));
        _;
    }
}

contract Zoo is Bar {
    function fooBar (uint x) public onlyPrime (x) {
        // Here we know that x is prime!
    }
}
0
0
pragma solidity ^0.8.15;

import {ListStorage} from "../storage/ListStorage.sol";

interface IListExtension {
    modifier isActiveList(
        address _tokenAddress,
        uint256 _tokenId,
        address _owner
    ) {
        require(ListStorage.isListed(_tokenAddress, _tokenId, _owner));
        _;
    }
}

pragma solidity ^0.8.15;

library ListStorage {
    struct Listing {
        uint256 listingId;
        address seller;
        address payToken;
        address tokenAddress;
        uint256 tokenId;
        uint256 quantity;
        uint256 boughtQuantity;
        uint256 priceInUsd;
        uint256 timeCreated;
        uint256 timeLastPurchased;
        bool sold;
        bool cancelled;
        bool isERC1155;
    }
    struct Layout {
        uint256 nextListingId;
        mapping(uint256 => Listing) listings;
        mapping(address => mapping(uint256 => mapping(address => uint256))) tokenToListingId;
        uint256[] listingIds;
    }

    bytes32 internal constant STORAGE_SLOT =
        keccak256("sokos.contracts.storage.listing");

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = STORAGE_SLOT;
        assembly {
            l.slot := slot
        }
    }

    function isListed(
        address _tokenAddress,
        uint256 _tokenId,
        address _owner
    ) public view returns (bool) {
        Layout storage l = ListStorage.layout();
        uint256 listingId = l.tokenToListingId[_tokenAddress][_tokenId][_owner];

        Listing memory listing = l.listings[listingId];
        require(!listing.cancelled && !listing.sold, "NOT_LISTED");
        return true;
    }
}
1
  • 1
    Please add an explanation. Just posting code is hard to understand and may not be useful for readers with little understanding. It is difficult to see what you are trying to show precisely.
    – Torof
    Commented Aug 25, 2023 at 2:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.