diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..12b3a7862 Binary files /dev/null and b/.DS_Store differ diff --git a/contracts/drop/DropERC1155.sol b/contracts/drop/DropERC1155.sol index f5fbefabd..4038104d8 100644 --- a/contracts/drop/DropERC1155.sol +++ b/contracts/drop/DropERC1155.sol @@ -597,6 +597,12 @@ contract DropERC1155 is emit PrimarySaleRecipientUpdated(_saleRecipient); } + /// @dev Lets a contract admin set the recipient for all primary sales. + function setSaleRecipientForToken(uint256 _tokenId, address _saleRecipient) external onlyRole(DEFAULT_ADMIN_ROLE) { + saleRecipient[_tokenId] = _saleRecipient; + emit SaleRecipientForTokenUpdated(_tokenId, _saleRecipient); + } + /// @dev Lets a contract admin update the default royalty recipient and bps. function setDefaultRoyaltyInfo(address _royaltyRecipient, uint256 _royaltyBps) external diff --git a/contracts/feature/ContractMetadata.sol b/contracts/feature/ContractMetadata.sol index 70f9070d9..ccadd8fde 100644 --- a/contracts/feature/ContractMetadata.sol +++ b/contracts/feature/ContractMetadata.sol @@ -3,13 +3,23 @@ pragma solidity ^0.8.0; import "./interface/IContractMetadata.sol"; +/** + * Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI + * for you contract. + * + * Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea. + */ + abstract contract ContractMetadata is IContractMetadata { /// @dev Contract level metadata. string public override contractURI; /// @dev Lets a contract admin set the URI for contract-level metadata. function setContractURI(string memory _uri) external override { - require(_canSetContractURI(), "Not authorized"); + if (!_canSetContractURI()) { + revert ContractMetadata__NotAuthorized(); + } + _setupContractURI(_uri); } diff --git a/contracts/feature/DelayedReveal.sol b/contracts/feature/DelayedReveal.sol index d1db2638a..2f1dc3817 100644 --- a/contracts/feature/DelayedReveal.sol +++ b/contracts/feature/DelayedReveal.sol @@ -3,6 +3,11 @@ pragma solidity ^0.8.0; import "./interface/IDelayedReveal.sol"; +/** + * Thirdweb's `DelayedReveal` is a contract extension for base NFT contracts. It lets you create batches of + * 'delayed-reveal' NFTs. You can learn more about the usage of delayed reveal NFTs here - https://blog.thirdweb.com/delayed-reveal-nfts + */ + abstract contract DelayedReveal is IDelayedReveal { /// @dev Mapping from id of a batch of tokens => to encrypted base URI for the respective batch of tokens. mapping(uint256 => bytes) public encryptedBaseURI; @@ -13,14 +18,13 @@ abstract contract DelayedReveal is IDelayedReveal { } /// @dev Returns the decrypted i.e. revealed URI for a batch of tokens. - function getRevealURI(uint256 _batchId, bytes calldata _key) public returns (string memory revealedURI) { + function getRevealURI(uint256 _batchId, bytes calldata _key) public view returns (string memory revealedURI) { bytes memory encryptedURI = encryptedBaseURI[_batchId]; - require(encryptedURI.length != 0, "nothing to reveal."); + if (encryptedURI.length == 0) { + revert DelayedReveal__NothingToReveal(_batchId); + } revealedURI = string(encryptDecrypt(encryptedURI, _key)); - - // yash - added this, and removed view mutability - delete encryptedBaseURI[_batchId]; } /// @dev See: https://ethereum.stackexchange.com/questions/69825/decrypt-message-on-chain diff --git a/contracts/feature/DropSinglePhase.sol b/contracts/feature/DropSinglePhase.sol index 5c68cfa48..523e6abb0 100644 --- a/contracts/feature/DropSinglePhase.sol +++ b/contracts/feature/DropSinglePhase.sol @@ -1,16 +1,14 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; -import "./interface/IClaimConditionsSinglePhase.sol"; -import "./interface/IDrop.sol"; -import "./LazyMint.sol"; +import "./interface/IDropSinglePhase.sol"; import "../lib/MerkleProof.sol"; import "../lib/TWBitMaps.sol"; -abstract contract DropSinglePhase is LazyMint, IDrop, IClaimConditionsSinglePhase { +abstract contract DropSinglePhase is IDropSinglePhase { using TWBitMaps for TWBitMaps.BitMap; - /*///////////////////////////////////////////////////x//////////// + /*/////////////////////////////////////////////////////////////// State variables //////////////////////////////////////////////////////////////*/ @@ -36,6 +34,10 @@ abstract contract DropSinglePhase is LazyMint, IDrop, IClaimConditionsSinglePhas */ mapping(bytes32 => TWBitMaps.BitMap) private usedAllowlistSpot; + /*/////////////////////////////////////////////////////////////// + Errors + //////////////////////////////////////////////////////////////*/ + /*/////////////////////////////////////////////////////////////// Drop logic //////////////////////////////////////////////////////////////*/ @@ -68,7 +70,10 @@ abstract contract DropSinglePhase is LazyMint, IDrop, IClaimConditionsSinglePhas ); // Verify claim validity. If not valid, revert. - bool toVerifyMaxQuantityPerTransaction = _allowlistProof.maxQuantityInAllowlist == 0; + // when there's allowlist present --> verifyClaimMerkleProof will verify the maxQuantityInAllowlist value with hashed leaf in the allowlist + // when there's no allowlist, this check is true --> verifyClaim will check for _quantity being equal/less than the limit + bool toVerifyMaxQuantityPerTransaction = _allowlistProof.maxQuantityInAllowlist == 0 || + claimCondition.merkleRoot == bytes32(0); verifyClaim(_dropMsgSender(), _quantity, _currency, _pricePerToken, toVerifyMaxQuantityPerTransaction); @@ -90,14 +95,16 @@ abstract contract DropSinglePhase is LazyMint, IDrop, IClaimConditionsSinglePhas // Mint the relevant NFTs to claimer. uint256 startTokenId = transferTokensOnClaim(_receiver, _quantity); - emit TokensClaimed(0, _dropMsgSender(), _receiver, startTokenId, _quantity); + emit TokensClaimed(_dropMsgSender(), _receiver, startTokenId, _quantity); _afterClaim(_receiver, _quantity, _currency, _pricePerToken, _allowlistProof, _data); } /// @dev Lets a contract admin set claim conditions. function setClaimConditions(ClaimCondition calldata _condition, bool _resetClaimEligibility) external override { - require(_canSetClaimConditions(), "Not authorized"); + if (!_canSetClaimConditions()) { + revert DropSinglePhase__NotAuthorized(); + } bytes32 targetConditionId = conditionId; uint256 supplyClaimedAlready = claimCondition.supplyClaimed; @@ -107,7 +114,9 @@ abstract contract DropSinglePhase is LazyMint, IDrop, IClaimConditionsSinglePhas targetConditionId = keccak256(abi.encodePacked(_dropMsgSender(), block.number)); } - require(supplyClaimedAlready <= _condition.maxClaimableSupply, "max supply claimed already"); + if (supplyClaimedAlready > _condition.maxClaimableSupply) { + revert DropSinglePhase__MaxSupplyClaimedAlready(supplyClaimedAlready); + } claimCondition = ClaimCondition({ startTimestamp: _condition.startTimestamp, @@ -134,24 +143,42 @@ abstract contract DropSinglePhase is LazyMint, IDrop, IClaimConditionsSinglePhas ) public view { ClaimCondition memory currentClaimPhase = claimCondition; - require( - _currency == currentClaimPhase.currency && _pricePerToken == currentClaimPhase.pricePerToken, - "invalid currency or price." - ); + if (_currency != currentClaimPhase.currency || _pricePerToken != currentClaimPhase.pricePerToken) { + revert DropSinglePhase__InvalidCurrencyOrPrice( + _currency, + currentClaimPhase.currency, + _pricePerToken, + currentClaimPhase.pricePerToken + ); + } // If we're checking for an allowlist quantity restriction, ignore the general quantity restriction. - require( - _quantity > 0 && - (!verifyMaxQuantityPerTransaction || _quantity <= currentClaimPhase.quantityLimitPerTransaction), - "invalid quantity." - ); - require( - currentClaimPhase.supplyClaimed + _quantity <= currentClaimPhase.maxClaimableSupply, - "exceed max claimable supply." - ); + if ( + _quantity == 0 || + (verifyMaxQuantityPerTransaction && _quantity > currentClaimPhase.quantityLimitPerTransaction) + ) { + revert DropSinglePhase__InvalidQuantity(); + } + + if (currentClaimPhase.supplyClaimed + _quantity > currentClaimPhase.maxClaimableSupply) { + revert DropSinglePhase__ExceedMaxClaimableSupply( + currentClaimPhase.supplyClaimed, + currentClaimPhase.maxClaimableSupply + ); + } (uint256 lastClaimedAt, uint256 nextValidClaimTimestamp) = getClaimTimestamp(_claimer); - require(lastClaimedAt == 0 || block.timestamp >= nextValidClaimTimestamp, "cannot claim."); + if ( + currentClaimPhase.startTimestamp > block.timestamp || + (lastClaimedAt != 0 && block.timestamp < nextValidClaimTimestamp) + ) { + revert DropSinglePhase__CannotClaimYet( + block.timestamp, + currentClaimPhase.startTimestamp, + lastClaimedAt, + nextValidClaimTimestamp + ); + } } /// @dev Checks whether a claimer meets the claim condition's allowlist criteria. @@ -168,12 +195,17 @@ abstract contract DropSinglePhase is LazyMint, IDrop, IClaimConditionsSinglePhas currentClaimPhase.merkleRoot, keccak256(abi.encodePacked(_claimer, _allowlistProof.maxQuantityInAllowlist)) ); - require(validMerkleProof, "not in whitelist."); - require(!usedAllowlistSpot[conditionId].get(merkleProofIndex), "proof claimed."); - require( - _allowlistProof.maxQuantityInAllowlist == 0 || _quantity <= _allowlistProof.maxQuantityInAllowlist, - "invalid quantity proof." - ); + if (!validMerkleProof) { + revert DropSinglePhase__NotInWhitelist(); + } + + if (usedAllowlistSpot[conditionId].get(merkleProofIndex)) { + revert DropSinglePhase__ProofClaimed(); + } + + if (_allowlistProof.maxQuantityInAllowlist != 0 && _quantity > _allowlistProof.maxQuantityInAllowlist) { + revert DropSinglePhase__InvalidQuantityProof(_allowlistProof.maxQuantityInAllowlist); + } } } diff --git a/contracts/feature/LazyMint.sol b/contracts/feature/LazyMint.sol index 46762492e..7084bcde1 100644 --- a/contracts/feature/LazyMint.sol +++ b/contracts/feature/LazyMint.sol @@ -3,6 +3,12 @@ pragma solidity ^0.8.0; import "./interface/ILazyMint.sol"; +/** + * Thirdweb's `LazyMint` is a contract extension for any base NFT contract. It lets you 'lazy mint' any number of NFTs + * at once. Here, 'lazy mint' means defining the metadata for particular tokenIds of your NFT contract, without actually + * minting a non-zero balance of NFTs of those tokenIds. + */ + abstract contract LazyMint is ILazyMint { /// @dev Largest tokenId of each batch of tokens with the same baseURI. uint256[] private batchIds; @@ -17,7 +23,9 @@ abstract contract LazyMint is ILazyMint { /// @dev Returns the id for the batch of tokens the given tokenId belongs to. function getBatchIdAtIndex(uint256 _index) public view returns (uint256) { - require(_index < getBaseURICount(), "invalid index."); + if (_index >= getBaseURICount()) { + revert LazyMint__InvalidIndex(_index); + } return batchIds[_index]; } @@ -32,7 +40,7 @@ abstract contract LazyMint is ILazyMint { } } - revert("No batch id for token."); + revert LazyMint__NoBatchIDForToken(_tokenId); } /// @dev Returns the baseURI for a token. The intended metadata URI for the token is baseURI + tokenId. @@ -46,7 +54,7 @@ abstract contract LazyMint is ILazyMint { } } - revert("No base URI for token."); + revert LazyMint__NoBaseURIForToken(_tokenId); } /// @dev Sets the base URI for the batch of tokens with the given batchId. diff --git a/contracts/feature/LazyMintERC721.sol b/contracts/feature/LazyMintERC721.sol index 793b0a8a2..265c8975c 100644 --- a/contracts/feature/LazyMintERC721.sol +++ b/contracts/feature/LazyMintERC721.sol @@ -7,7 +7,7 @@ import "../lib/TWStrings.sol"; abstract contract LazyMintERC721 is LazyMint { using TWStrings for uint256; - event TokensLazyMinted(uint256 startTokenId, uint256 endTokenId, string baseURI, bytes extraData); + event TokensLazyMinted(uint256 indexed startTokenId, uint256 endTokenId, string baseURI, bytes extraData); /// @dev the next available non-minted token id uint256 public nextTokenIdToMint; diff --git a/contracts/feature/Ownable.sol b/contracts/feature/Ownable.sol index d1ad3fc36..66b4acfd7 100644 --- a/contracts/feature/Ownable.sol +++ b/contracts/feature/Ownable.sol @@ -3,13 +3,21 @@ pragma solidity ^0.8.0; import "./interface/IOwnable.sol"; +/** + * Thirdweb's `Ownable` is a contract extension to be used with any base contract. It exposes functions for setting and reading + * who the 'owner' of the inheriting smart contract is, and lets the inheriting contract perform conditional logic that uses + * information about who the contract's owner is. + */ + abstract contract Ownable is IOwnable { /// @dev Owner of the contract (purpose: OpenSea compatibility) address public override owner; /// @dev Lets a contract admin set a new owner for the contract. The new owner must be a contract admin. function setOwner(address _newOwner) external override { - require(_canSetOwner(), "Not authorized"); + if (!_canSetOwner()) { + revert Ownable__NotAuthorized(); + } _setupOwner(_newOwner); } diff --git a/contracts/feature/Permissions.sol b/contracts/feature/Permissions.sol index d990737d6..5ac7ead4c 100644 --- a/contracts/feature/Permissions.sol +++ b/contracts/feature/Permissions.sol @@ -27,12 +27,15 @@ contract Permissions is IPermissions { return true; } - function getRoleAdmin(bytes32 role) public view override returns (bytes32) { + function getRoleAdmin(bytes32 role) external view override returns (bytes32) { return _getRoleAdmin[role]; } function grantRole(bytes32 role, address account) public virtual override { _checkRole(_getRoleAdmin[role], msg.sender); + if (_hasRole[role][account]) { + revert Permissions__CanOnlyGrantToNonHolders(account); + } _setupRole(role, account); } @@ -42,7 +45,9 @@ contract Permissions is IPermissions { } function renounceRole(bytes32 role, address account) public virtual override { - require(msg.sender == account, "Can only renounce for self"); + if (msg.sender != account) { + revert Permissions__CanOnlyRenounceForSelf(msg.sender, account); + } _revokeRole(role, account); } @@ -58,6 +63,7 @@ contract Permissions is IPermissions { } function _revokeRole(bytes32 role, address account) internal virtual { + _checkRole(role, account); delete _hasRole[role][account]; emit RoleRevoked(role, account, msg.sender); } diff --git a/contracts/feature/PermissionsEnumerable.sol b/contracts/feature/PermissionsEnumerable.sol index 035bb898f..afa0e3b64 100644 --- a/contracts/feature/PermissionsEnumerable.sol +++ b/contracts/feature/PermissionsEnumerable.sol @@ -21,6 +21,7 @@ contract PermissionsEnumerable is IPermissionsEnumerable, Permissions { if (roleMembers[role].members[i] != address(0)) { if (check == index) { member = roleMembers[role].members[i]; + return member; } } else { check += 1; @@ -38,18 +39,8 @@ contract PermissionsEnumerable is IPermissionsEnumerable, Permissions { } } - function grantRole(bytes32 role, address account) public override(IPermissions, Permissions) { - super.grantRole(role, account); - _addMember(role, account); - } - - function revokeRole(bytes32 role, address account) public override(IPermissions, Permissions) { - super.revokeRole(role, account); - _removeMember(role, account); - } - - function renounceRole(bytes32 role, address account) public override(IPermissions, Permissions) { - super.renounceRole(role, account); + function _revokeRole(bytes32 role, address account) internal override { + super._revokeRole(role, account); _removeMember(role, account); } diff --git a/contracts/feature/PlatformFee.sol b/contracts/feature/PlatformFee.sol index f2669a34d..786f8812a 100644 --- a/contracts/feature/PlatformFee.sol +++ b/contracts/feature/PlatformFee.sol @@ -3,6 +3,12 @@ pragma solidity ^0.8.0; import "./interface/IPlatformFee.sol"; +/** + * Thirdweb's `PlatformFee` is a contract extension to be used with any base contract. It exposes functions for setting and reading + * the recipient of platform fee and the platform fee basis points, and lets the inheriting contract perform conditional logic + * that uses information about platform fees, if desired. + */ + abstract contract PlatformFee is IPlatformFee { /// @dev The address that receives all platform fees from all sales. address private platformFeeRecipient; @@ -17,13 +23,17 @@ abstract contract PlatformFee is IPlatformFee { /// @dev Lets a contract admin update the platform fee recipient and bps function setPlatformFeeInfo(address _platformFeeRecipient, uint256 _platformFeeBps) external override { - require(_canSetPlatformFeeInfo(), "Not authorized"); + if (!_canSetPlatformFeeInfo()) { + revert PlatformFee__NotAuthorized(); + } _setupPlatformFeeInfo(_platformFeeRecipient, _platformFeeBps); } /// @dev Lets a contract admin update the platform fee recipient and bps function _setupPlatformFeeInfo(address _platformFeeRecipient, uint256 _platformFeeBps) internal { - require(_platformFeeBps <= 10_000, "Exceeds max bps"); + if (_platformFeeBps > 10_000) { + revert PlatformFee__ExceedsMaxBps(_platformFeeBps); + } platformFeeBps = uint16(_platformFeeBps); platformFeeRecipient = _platformFeeRecipient; diff --git a/contracts/feature/PrimarySale.sol b/contracts/feature/PrimarySale.sol index 4f5cc543c..bef0fd5f0 100644 --- a/contracts/feature/PrimarySale.sol +++ b/contracts/feature/PrimarySale.sol @@ -3,6 +3,12 @@ pragma solidity ^0.8.0; import "./interface/IPrimarySale.sol"; +/** + * Thirdweb's `Primary` is a contract extension to be used with any base contract. It exposes functions for setting and reading + * the recipient of primary sales, and lets the inheriting contract perform conditional logic that uses information about + * primary sales, if desired. + */ + abstract contract PrimarySale is IPrimarySale { /// @dev The address that receives all primary sales value. address private recipient; @@ -13,7 +19,9 @@ abstract contract PrimarySale is IPrimarySale { /// @dev Lets a contract admin set the recipient for all primary sales. function setPrimarySaleRecipient(address _saleRecipient) external override { - require(_canSetPrimarySaleRecipient(), "Not authorized"); + if (!_canSetPrimarySaleRecipient()) { + revert PrimarySale__NotAuthorized(); + } _setupPrimarySaleRecipient(_saleRecipient); } diff --git a/contracts/feature/Royalty.sol b/contracts/feature/Royalty.sol index 4986fde2a..19c7ce9d5 100644 --- a/contracts/feature/Royalty.sol +++ b/contracts/feature/Royalty.sol @@ -3,6 +3,14 @@ pragma solidity ^0.8.0; import "./interface/IRoyalty.sol"; +/** + * Thirdweb's `Royalty` is a contract extension to be used with any base contract. It exposes functions for setting and reading + * the recipient of royalty fee and the royalty fee basis points, and lets the inheriting contract perform conditional logic + * that uses information about royalty fees, if desired. + * + * The `Royalty` contract is ERC2981 compliant. + */ + abstract contract Royalty is IRoyalty { /// @dev The (default) address that receives all royalty value. address private royaltyRecipient; @@ -43,13 +51,18 @@ abstract contract Royalty is IRoyalty { /// @dev Lets a contract admin update the default royalty recipient and bps. function setDefaultRoyaltyInfo(address _royaltyRecipient, uint256 _royaltyBps) external override { - require(_canSetRoyaltyInfo(), "Not authorized"); + if (!_canSetRoyaltyInfo()) { + revert Royalty__NotAuthorized(); + } + _setupDefaultRoyaltyInfo(_royaltyRecipient, _royaltyBps); } /// @dev Lets a contract admin update the default royalty recipient and bps. function _setupDefaultRoyaltyInfo(address _royaltyRecipient, uint256 _royaltyBps) internal { - require(_royaltyBps <= 10_000, "Exceeds max bps"); + if (_royaltyBps > 10_000) { + revert Royalty__ExceedsMaxBps(_royaltyBps); + } royaltyRecipient = _royaltyRecipient; royaltyBps = uint16(_royaltyBps); @@ -63,7 +76,10 @@ abstract contract Royalty is IRoyalty { address _recipient, uint256 _bps ) external override { - require(_canSetRoyaltyInfo(), "Not authorized"); + if (!_canSetRoyaltyInfo()) { + revert Royalty__NotAuthorized(); + } + _setupRoyaltyInfoForToken(_tokenId, _recipient, _bps); } @@ -73,7 +89,9 @@ abstract contract Royalty is IRoyalty { address _recipient, uint256 _bps ) internal { - require(_bps <= 10_000, "Exceeds max bps"); + if (_bps > 10_000) { + revert Royalty__ExceedsMaxBps(_bps); + } royaltyInfoForToken[_tokenId] = RoyaltyInfo({ recipient: _recipient, bps: _bps }); diff --git a/contracts/feature/SignatureMintERC721.sol b/contracts/feature/SignatureMintERC721.sol index 2e8728b83..689e1a78f 100644 --- a/contracts/feature/SignatureMintERC721.sol +++ b/contracts/feature/SignatureMintERC721.sol @@ -38,11 +38,13 @@ abstract contract SignatureMintERC721 is EIP712, ISignatureMintERC721 { bool success; (success, signer) = verify(_req, _signature); - require(success, "Invalid request"); - require( - _req.validityStartTimestamp <= block.timestamp && block.timestamp <= _req.validityEndTimestamp, - "Request expired" - ); + if (!success) { + revert SignatureMintERC721__InvalidRequest(); + } + + if (_req.validityStartTimestamp > block.timestamp || block.timestamp > _req.validityEndTimestamp) { + revert SignatureMintERC721__RequestExpired(block.timestamp); + } minted[_req.uid] = true; } diff --git a/contracts/feature/SignatureMintERC721Upgradeable.sol b/contracts/feature/SignatureMintERC721Upgradeable.sol index 587d9c99f..6ed984e6e 100644 --- a/contracts/feature/SignatureMintERC721Upgradeable.sol +++ b/contracts/feature/SignatureMintERC721Upgradeable.sol @@ -42,11 +42,13 @@ abstract contract SignatureMintERC721Upgradeable is Initializable, EIP712Upgrade bool success; (success, signer) = verify(_req, _signature); - require(success, "Invalid request"); - require( - _req.validityStartTimestamp <= block.timestamp && block.timestamp <= _req.validityEndTimestamp, - "Request expired" - ); + if (!success) { + revert SignatureMintERC721__InvalidRequest(); + } + + if (_req.validityStartTimestamp > block.timestamp || block.timestamp > _req.validityEndTimestamp) { + revert SignatureMintERC721__RequestExpired(block.timestamp); + } minted[_req.uid] = true; } diff --git a/contracts/feature/TokenBundle.sol b/contracts/feature/TokenBundle.sol index d18b1c0a5..74ed98f9b 100644 --- a/contracts/feature/TokenBundle.sol +++ b/contracts/feature/TokenBundle.sol @@ -22,8 +22,22 @@ abstract contract TokenBundle is ITokenBundle { return bundle[_bundleId].uri; } - /// @dev Lets the calling contract create/update a bundle, by passing in a list of tokens and a unique id. - function _setBundle(Token[] calldata _tokensToBind, uint256 _bundleId) internal { + /// @dev Lets the calling contract create a bundle, by passing in a list of tokens and a unique id. + function _createBundle(Token[] calldata _tokensToBind, uint256 _bundleId) internal { + uint256 targetCount = _tokensToBind.length; + + require(targetCount > 0, "TokenBundle: no tokens to bind."); + require(bundle[_bundleId].count == 0, "TokenBundle: existent at bundleId"); + + for (uint256 i = 0; i < targetCount; i += 1) { + bundle[_bundleId].tokens[i] = _tokensToBind[i]; + } + + bundle[_bundleId].count = targetCount; + } + + /// @dev Lets the calling contract update a bundle, by passing in a list of tokens and a unique id. + function _updateBundle(Token[] calldata _tokensToBind, uint256 _bundleId) internal { require(_tokensToBind.length > 0, "TokenBundle: no tokens to bind."); uint256 currentCount = bundle[_bundleId].count; diff --git a/contracts/feature/TokenStore.sol b/contracts/feature/TokenStore.sol index 0319f4b79..9c2726bcc 100644 --- a/contracts/feature/TokenStore.sol +++ b/contracts/feature/TokenStore.sol @@ -32,7 +32,7 @@ contract TokenStore is TokenBundle, ERC721Holder, ERC1155Holder { string calldata _uriForTokens, uint256 _idForTokens ) internal { - _setBundle(_tokens, _idForTokens); + _createBundle(_tokens, _idForTokens); _setUriOfBundle(_uriForTokens, _idForTokens); _transferTokenBatch(_tokenOwner, address(this), _tokens); } @@ -80,7 +80,7 @@ contract TokenStore is TokenBundle, ERC721Holder, ERC1155Holder { ) internal { uint256 nativeTokenValue; for (uint256 i = 0; i < _tokens.length; i += 1) { - if (_tokens[i].assetContract == NATIVE_TOKEN && _to == address(this)) { + if (_tokens[i].assetContract == CurrencyTransferLib.NATIVE_TOKEN && _to == address(this)) { nativeTokenValue += _tokens[i].totalAmount; } else { _transferToken(_from, _to, _tokens[i]); @@ -88,7 +88,7 @@ contract TokenStore is TokenBundle, ERC721Holder, ERC1155Holder { } if (nativeTokenValue != 0) { Token memory _nativeToken = Token({ - assetContract: NATIVE_TOKEN, + assetContract: CurrencyTransferLib.NATIVE_TOKEN, tokenType: ITokenBundle.TokenType.ERC20, tokenId: 0, totalAmount: nativeTokenValue diff --git a/contracts/feature/interface/IContractMetadata.sol b/contracts/feature/interface/IContractMetadata.sol index bf61c4979..b476f698f 100644 --- a/contracts/feature/interface/IContractMetadata.sol +++ b/contracts/feature/interface/IContractMetadata.sol @@ -1,6 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; +/** + * Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI + * for you contract. + * + * Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea. + */ + interface IContractMetadata { /// @dev Returns the metadata URI of the contract. function contractURI() external view returns (string memory); @@ -11,5 +18,9 @@ interface IContractMetadata { */ function setContractURI(string calldata _uri) external; + /// @dev Emitted when the contract URI is updated. event ContractURIUpdated(string prevURI, string newURI); + + /// @dev Emitted when an unauthorized caller tries to set the contract metadata URI. + error ContractMetadata__NotAuthorized(); } diff --git a/contracts/feature/interface/IDelayedReveal.sol b/contracts/feature/interface/IDelayedReveal.sol index 51d96ff7f..25e4e3b55 100644 --- a/contracts/feature/interface/IDelayedReveal.sol +++ b/contracts/feature/interface/IDelayedReveal.sol @@ -1,8 +1,31 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; +/** + * Thirdweb's `DelayedReveal` is a contract extension for base NFT contracts. It lets you create batches of + * 'delayed-reveal' NFTs. You can learn more about the usage of delayed reveal NFTs here - https://blog.thirdweb.com/delayed-reveal-nfts + */ + interface IDelayedReveal { + /// @notice Emitted when encrypted URI for a given batch is empty. + error DelayedReveal__NothingToReveal(uint256 batchId); + + /** + * @notice Reveals a batch of delayed reveal NFTs. + * + * @param identifier The ID for the batch of delayed-reveal NFTs to reveal. + * + * @param key The key with which the base URI for the relevant batch of NFTs was encrypted. + */ function reveal(uint256 identifier, bytes calldata key) external returns (string memory revealedURI); + /** + * @notice Performs XOR encryption/decryption. + * + * @param data The data to encrypt. In the case of delayed-reveal NFTs, this is the "revealed" state + * base URI of the relevant batch of NFTs. + * + * @param key The key with which to encrypt data + */ function encryptDecrypt(bytes memory data, bytes calldata key) external pure returns (bytes memory result); } diff --git a/contracts/feature/interface/IDropSinglePhase.sol b/contracts/feature/interface/IDropSinglePhase.sol new file mode 100644 index 000000000..1875ec064 --- /dev/null +++ b/contracts/feature/interface/IDropSinglePhase.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.0; + +import "./IClaimCondition.sol"; + +interface IDropSinglePhase is IClaimCondition { + struct AllowlistProof { + bytes32[] proof; + uint256 maxQuantityInAllowlist; + } + + /// @dev Emitted when an unauthorized caller tries to set claim conditions. + error DropSinglePhase__NotAuthorized(); + + /// @notice Emitted when given currency or price is invalid. + error DropSinglePhase__InvalidCurrencyOrPrice( + address givenCurrency, + address requiredCurrency, + uint256 givenPricePerToken, + uint256 requiredPricePerToken + ); + + /// @notice Emitted when claiming invalid quantity of tokens. + error DropSinglePhase__InvalidQuantity(); + + /// @notice Emitted when claiming given quantity will exceed max claimable supply. + error DropSinglePhase__ExceedMaxClaimableSupply(uint256 supplyClaimed, uint256 maxClaimableSupply); + + /// @notice Emitted when the current timestamp is invalid for claim. + error DropSinglePhase__CannotClaimYet( + uint256 blockTimestamp, + uint256 startTimestamp, + uint256 lastClaimedAt, + uint256 nextValidClaimTimestamp + ); + + /// @notice Emitted when given allowlist proof is invalid. + error DropSinglePhase__NotInWhitelist(); + + /// @notice Emitted when allowlist spot is already used. + error DropSinglePhase__ProofClaimed(); + + /// @notice Emitted when claiming more than allowed quantity in allowlist. + error DropSinglePhase__InvalidQuantityProof(uint256 maxQuantityInAllowlist); + + /// @notice Emitted when max claimable supply in given condition is less than supply claimed already. + error DropSinglePhase__MaxSupplyClaimedAlready(uint256 supplyClaimedAlready); + + /// @dev Emitted when tokens are claimed via `claim`. + event TokensClaimed( + address indexed claimer, + address indexed receiver, + uint256 indexed startTokenId, + uint256 quantityClaimed + ); + + /// @dev Emitted when the contract's claim conditions are updated. + event ClaimConditionUpdated(ClaimCondition condition, bool resetEligibility); + + /** + * @notice Lets an account claim a given quantity of NFTs. + * + * @param receiver The receiver of the NFTs to claim. + * @param quantity The quantity of NFTs to claim. + * @param currency The currency in which to pay for the claim. + * @param pricePerToken The price per token to pay for the claim. + * @param allowlistProof The proof of the claimer's inclusion in the merkle root allowlist + * of the claim conditions that apply. + * @param data Arbitrary bytes data that can be leveraged in the implementation of this interface. + */ + function claim( + address receiver, + uint256 quantity, + address currency, + uint256 pricePerToken, + AllowlistProof calldata allowlistProof, + bytes memory data + ) external payable; + + /** + * @notice Lets a contract admin (account with `DEFAULT_ADMIN_ROLE`) set claim conditions. + * + * @param phase Claim condition to set. + * + * @param resetClaimEligibility Whether to reset `limitLastClaimTimestamp` and `limitMerkleProofClaim` values when setting new + * claim conditions. + */ + function setClaimConditions(ClaimCondition calldata phase, bool resetClaimEligibility) external; +} diff --git a/contracts/feature/interface/ILazyMint.sol b/contracts/feature/interface/ILazyMint.sol index 924268c97..a17653ae5 100644 --- a/contracts/feature/interface/ILazyMint.sol +++ b/contracts/feature/interface/ILazyMint.sol @@ -1,7 +1,34 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; +/** + * Thirdweb's `LazyMint` is a contract extension for any base NFT contract. It lets you 'lazy mint' any number of NFTs + * at once. Here, 'lazy mint' means defining the metadata for particular tokenIds of your NFT contract, without actually + * minting a non-zero balance of NFTs of those tokenIds. + */ + interface ILazyMint { + /// @notice Emitted when the given index is equal to or higher than total number of batches. + error LazyMint__InvalidIndex(uint256 index); + + /// @notice Emitted when the given token ID doesn't belong to any batch. + error LazyMint__NoBatchIDForToken(uint256 tokenId); + + /// @notice Emitted when there's no Base URI set for the given token ID. + error LazyMint__NoBaseURIForToken(uint256 tokenId); + + /** + * @notice Lazy mints a given amount of NFTs. + * + * @param amount The number of NFTs to lazy mint. + * + * @param baseURIForTokens The base URI for the 'n' number of NFTs being lazy minted, where the metadata for each + * of those NFTs is `${baseURIForTokens}/${tokenId}`. + * + * @param extraData Additional bytes data to be used at the discretion of the consumer of the contract. + * + * @return batchId A unique integer identifier for the batch of NFTs lazy minted together. + */ function lazyMint( uint256 amount, string calldata baseURIForTokens, diff --git a/contracts/feature/interface/IOwnable.sol b/contracts/feature/interface/IOwnable.sol index 05b5a7eb5..c94c1b2ee 100644 --- a/contracts/feature/interface/IOwnable.sol +++ b/contracts/feature/interface/IOwnable.sol @@ -1,6 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; +/** + * Thirdweb's `Ownable` is a contract extension to be used with any base contract. It exposes functions for setting and reading + * who the 'owner' of the inheriting smart contract is, and lets the inheriting contract perform conditional logic that uses + * information about who the contract's owner is. + */ + interface IOwnable { /// @dev Returns the owner of the contract. function owner() external view returns (address); @@ -9,5 +15,8 @@ interface IOwnable { function setOwner(address _newOwner) external; /// @dev Emitted when a new Owner is set. - event OwnerUpdated(address prevOwner, address newOwner); + event OwnerUpdated(address indexed prevOwner, address indexed newOwner); + + /// @dev Emitted when an unauthorized caller tries to set the owner. + error Ownable__NotAuthorized(); } diff --git a/contracts/feature/interface/IPermissions.sol b/contracts/feature/interface/IPermissions.sol index bee59b57d..74ff3f108 100644 --- a/contracts/feature/interface/IPermissions.sol +++ b/contracts/feature/interface/IPermissions.sol @@ -5,6 +5,12 @@ pragma solidity ^0.8.0; * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IPermissions { + /// @notice Emitted when calling address is different from the specified account. + error Permissions__CanOnlyRenounceForSelf(address caller, address account); + + /// @notice Emitted when specified account already has the role. + error Permissions__CanOnlyGrantToNonHolders(address account); + /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * @@ -37,6 +43,12 @@ interface IPermissions { */ function hasRole(bytes32 role, address account) external view returns (bool); + /** + * @dev Returns `true` if either (1) `account` has been granted `role`, or (2) the relevant role restrictions + * do not apply at the time of calling this function. + */ + function hasRoleWithSwitch(bytes32 role, address account) external view returns (bool); + /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. diff --git a/contracts/feature/interface/IPlatformFee.sol b/contracts/feature/interface/IPlatformFee.sol index 0ae86394e..41edabc3e 100644 --- a/contracts/feature/interface/IPlatformFee.sol +++ b/contracts/feature/interface/IPlatformFee.sol @@ -1,7 +1,16 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; +/** + * Thirdweb's `PlatformFee` is a contract extension to be used with any base contract. It exposes functions for setting and reading + * the recipient of platform fee and the platform fee basis points, and lets the inheriting contract perform conditional logic + * that uses information about platform fees, if desired. + */ + interface IPlatformFee { + /// @notice Emitted when given platform-fee bps exceeds max bps. + error PlatformFee__ExceedsMaxBps(uint256 platformFeeBps); + /// @dev Returns the platform fee bps and recipient. function getPlatformFeeInfo() external view returns (address, uint16); @@ -9,5 +18,8 @@ interface IPlatformFee { function setPlatformFeeInfo(address _platformFeeRecipient, uint256 _platformFeeBps) external; /// @dev Emitted when fee on primary sales is updated. - event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBps); + event PlatformFeeInfoUpdated(address indexed platformFeeRecipient, uint256 platformFeeBps); + + /// @dev Emitted when an unauthorized caller tries to set platform fee details. + error PlatformFee__NotAuthorized(); } diff --git a/contracts/feature/interface/IPrimarySale.sol b/contracts/feature/interface/IPrimarySale.sol index af9de95cf..3bca8cb97 100644 --- a/contracts/feature/interface/IPrimarySale.sol +++ b/contracts/feature/interface/IPrimarySale.sol @@ -1,6 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; +/** + * Thirdweb's `Primary` is a contract extension to be used with any base contract. It exposes functions for setting and reading + * the recipient of primary sales, and lets the inheriting contract perform conditional logic that uses information about + * primary sales, if desired. + */ + interface IPrimarySale { /// @dev The adress that receives all primary sales value. function primarySaleRecipient() external view returns (address); @@ -10,4 +16,7 @@ interface IPrimarySale { /// @dev Emitted when a new sale recipient is set. event PrimarySaleRecipientUpdated(address indexed recipient); + + /// @dev Emitted when an unauthorized caller tries to set primary sales details. + error PrimarySale__NotAuthorized(); } diff --git a/contracts/feature/interface/IRoyalty.sol b/contracts/feature/interface/IRoyalty.sol index 708b82837..7d299957d 100644 --- a/contracts/feature/interface/IRoyalty.sol +++ b/contracts/feature/interface/IRoyalty.sol @@ -1,12 +1,26 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; +/** + * Thirdweb's `Royalty` is a contract extension to be used with any base contract. It exposes functions for setting and reading + * the recipient of royalty fee and the royalty fee basis points, and lets the inheriting contract perform conditional logic + * that uses information about royalty fees, if desired. + * + * The `Royalty` contract is ERC2981 compliant. + */ + interface IRoyalty { struct RoyaltyInfo { address recipient; uint256 bps; } + /// @notice Emitted when the given bps exceeds max bps. + error Royalty__ExceedsMaxBps(uint256 royaltyBps); + + /// @dev Emitted when an unauthorized caller tries to set royalty details. + error Royalty__NotAuthorized(); + /// @dev Returns the royalty recipient and fee bps. function getDefaultRoyaltyInfo() external view returns (address, uint16); @@ -33,8 +47,8 @@ interface IRoyalty { returns (address receiver, uint256 royaltyAmount); /// @dev Emitted when royalty info is updated. - event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps); + event DefaultRoyalty(address indexed newRoyaltyRecipient, uint256 newRoyaltyBps); /// @dev Emitted when royalty recipient for tokenId is set - event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 royaltyBps); + event RoyaltyForToken(uint256 indexed tokenId, address indexed royaltyRecipient, uint256 royaltyBps); } diff --git a/contracts/feature/interface/ISignatureMintERC721.sol b/contracts/feature/interface/ISignatureMintERC721.sol index 0edfd9769..681890319 100644 --- a/contracts/feature/interface/ISignatureMintERC721.sol +++ b/contracts/feature/interface/ISignatureMintERC721.sol @@ -9,6 +9,12 @@ pragma solidity ^0.8.0; * minted by that external party. */ interface ISignatureMintERC721 { + /// @notice Emitted when either the signature or the request uid is invalid. + error SignatureMintERC721__InvalidRequest(); + + /// @notice Emitted when block-timestamp is outside of validity start and end range. + error SignatureMintERC721__RequestExpired(uint256 blockTimestamp); + /** * @notice The body of a request to mint tokens. * diff --git a/contracts/interfaces/drop/IDropERC1155.sol b/contracts/interfaces/drop/IDropERC1155.sol index 3f30dff71..bbd443d56 100644 --- a/contracts/interfaces/drop/IDropERC1155.sol +++ b/contracts/interfaces/drop/IDropERC1155.sol @@ -46,6 +46,9 @@ interface IDropERC1155 is IERC1155Upgradeable, IDropClaimCondition { /// @dev Emitted when the max wallet claim count for a given tokenId is updated. event MaxWalletClaimCountUpdated(uint256 tokenId, uint256 count); + /// @dev Emitted when the sale recipient for a particular tokenId is updated. + event SaleRecipientForTokenUpdated(uint256 indexed tokenId, address saleRecipient); + /** * @notice Lets an account with `MINTER_ROLE` lazy mint 'n' NFTs. * The URIs for each token is the provided `_baseURIForTokens` + `{tokenId}`. diff --git a/contracts/multiwrap/Multiwrap.sol b/contracts/multiwrap/Multiwrap.sol index 699d073f4..37736c94c 100644 --- a/contracts/multiwrap/Multiwrap.sol +++ b/contracts/multiwrap/Multiwrap.sol @@ -116,6 +116,11 @@ contract Multiwrap is return uint8(VERSION); } + /// @dev Lets the contract receive ether to unwrap native tokens. + receive() external payable { + require(msg.sender == nativeTokenWrapper, "caller not native token wrapper."); + } + /*/////////////////////////////////////////////////////////////// ERC 165 / 721 / 2981 logic //////////////////////////////////////////////////////////////*/ @@ -136,6 +141,7 @@ contract Multiwrap is return super.supportsInterface(interfaceId) || interfaceId == type(IERC721Upgradeable).interfaceId || + interfaceId == type(IERC1155Receiver).interfaceId || interfaceId == type(IERC2981Upgradeable).interfaceId; } @@ -167,8 +173,8 @@ contract Multiwrap is /// @dev Unwrap a wrapped NFT to retrieve underlying ERC1155, ERC721, ERC20 tokens. function unwrap(uint256 _tokenId, address _recipient) external nonReentrant onlyRoleWithSwitch(UNWRAP_ROLE) { - require(_tokenId < nextTokenIdToMint, "Multiwrap: wrapped NFT DNE."); - require(_isApprovedOrOwner(_msgSender(), _tokenId), "Multiwrap: caller not approved for unwrapping."); + require(_tokenId < nextTokenIdToMint, "wrapped NFT DNE."); + require(_isApprovedOrOwner(_msgSender(), _tokenId), "caller not approved for unwrapping."); _burn(_tokenId); _releaseTokens(_recipient, _tokenId); diff --git a/contracts/signature-drop/SignatureDrop.sol b/contracts/signature-drop/SignatureDrop.sol index f52199789..90daa7aef 100644 --- a/contracts/signature-drop/SignatureDrop.sol +++ b/contracts/signature-drop/SignatureDrop.sol @@ -22,6 +22,7 @@ import "../feature/Royalty.sol"; import "../feature/PrimarySale.sol"; import "../feature/Ownable.sol"; import "../feature/DelayedReveal.sol"; +import "../feature/LazyMint.sol"; import "../feature/PermissionsEnumerable.sol"; import "../feature/DropSinglePhase.sol"; import "../feature/SignatureMintERC721Upgradeable.sol"; @@ -34,6 +35,7 @@ contract SignatureDrop is PrimarySale, Ownable, DelayedReveal, + LazyMint, PermissionsEnumerable, DropSinglePhase, SignatureMintERC721Upgradeable, @@ -65,8 +67,27 @@ contract SignatureDrop is Events //////////////////////////////////////////////////////////////*/ - event TokensLazyMinted(uint256 startTokenId, uint256 endTokenId, string baseURI, bytes encryptedBaseURI); - event TokenURIRevealed(uint256 index, string revealedURI); + event TokensLazyMinted(uint256 indexed startTokenId, uint256 endTokenId, string baseURI, bytes encryptedBaseURI); + event TokenURIRevealed(uint256 indexed index, string revealedURI); + + /*/////////////////////////////////////////////////////////////// + Custom Errors + //////////////////////////////////////////////////////////////*/ + + /// @notice Emitted when minting the given quantity will exceed available quantity. + error SignatureDrop__NotEnoughMintedTokens(uint256 currentIndex, uint256 quantity); + + /// @notice Emitted when given quantity to mint is zero. + error SignatureDrop__MintingZeroTokens(); + + /// @notice Emitted when given amount for lazy-minting is zero. + error SignatureDrop__ZeroAmount(); + + /// @notice Emitted when sent value doesn't match the total price of tokens. + error SignatureDrop__MustSendTotalPrice(uint256 sentValue, uint256 totalPrice); + + /// @notice Emitted when given address doesn't have transfer role. + error SignatureDrop__NotTransferRole(); /*/////////////////////////////////////////////////////////////// Constructor + initializer logic @@ -151,6 +172,10 @@ contract SignatureDrop is string calldata _baseURIForTokens, bytes calldata _encryptedBaseURI ) external onlyRole(MINTER_ROLE) returns (uint256 batchId) { + if (_amount == 0) { + revert SignatureDrop__ZeroAmount(); + } + uint256 startId = nextTokenIdToMint; (nextTokenIdToMint, batchId) = _batchMint(startId, _amount, _baseURIForTokens); @@ -159,7 +184,7 @@ contract SignatureDrop is _setEncryptedBaseURI(batchId, _encryptedBaseURI); } - emit TokensLazyMinted(startId, startId + _amount, _baseURIForTokens, _encryptedBaseURI); + emit TokensLazyMinted(startId, startId + _amount - 1, _baseURIForTokens, _encryptedBaseURI); } /// @dev Lets an account with `MINTER_ROLE` reveal the URI for a batch of 'delayed-reveal' NFTs. @@ -171,6 +196,7 @@ contract SignatureDrop is uint256 batchId = getBatchIdAtIndex(_index); revealedURI = getRevealURI(batchId, _key); + _setEncryptedBaseURI(batchId, ""); _setBaseURI(batchId, revealedURI); emit TokenURIRevealed(_index, revealedURI); @@ -186,10 +212,14 @@ contract SignatureDrop is payable returns (address signer) { - require(_req.quantity > 0, "minting zero tokens"); + if (_req.quantity == 0) { + revert SignatureDrop__MintingZeroTokens(); + } uint256 tokenIdToMint = _currentIndex; - require(tokenIdToMint + _req.quantity <= nextTokenIdToMint, "not enough minted tokens."); + if (tokenIdToMint + _req.quantity > nextTokenIdToMint) { + revert SignatureDrop__NotEnoughMintedTokens(tokenIdToMint, _req.quantity); + } // Verify and process payload. signer = _processRequest(_req, _signature); @@ -225,7 +255,10 @@ contract SignatureDrop is AllowlistProof calldata, bytes memory ) internal view override { - require(_currentIndex + _quantity <= nextTokenIdToMint, "not enough minted tokens."); + require(isTrustedForwarder(msg.sender) || _msgSender() == tx.origin, "BOT"); + if (_currentIndex + _quantity > nextTokenIdToMint) { + revert SignatureDrop__NotEnoughMintedTokens(_currentIndex, _quantity); + } } /// @dev Collects and distributes the primary sale value of NFTs being claimed. @@ -244,7 +277,9 @@ contract SignatureDrop is uint256 platformFees = (totalPrice * platformFeeBps) / MAX_BPS; if (_currency == CurrencyTransferLib.NATIVE_TOKEN) { - require(msg.value == totalPrice, "must send total price."); + if (msg.value != totalPrice) { + revert SignatureDrop__MustSendTotalPrice(msg.value, totalPrice); + } } CurrencyTransferLib.transferCurrency(_currency, _msgSender(), platformFeeRecipient, platformFees); @@ -271,32 +306,32 @@ contract SignatureDrop is return hasRole(MINTER_ROLE, _signer); } - /// @dev Returns whether platform fee info can be set in the given execution context. + /// @dev Checks whether platform fee info can be set in the given execution context. function _canSetPlatformFeeInfo() internal view override returns (bool) { return hasRole(DEFAULT_ADMIN_ROLE, _msgSender()); } - /// @dev Returns whether primary sale recipient can be set in the given execution context. + /// @dev Checks whether primary sale recipient can be set in the given execution context. function _canSetPrimarySaleRecipient() internal view override returns (bool) { return hasRole(DEFAULT_ADMIN_ROLE, _msgSender()); } - /// @dev Returns whether owner can be set in the given execution context. + /// @dev Checks whether owner can be set in the given execution context. function _canSetOwner() internal view override returns (bool) { return hasRole(DEFAULT_ADMIN_ROLE, _msgSender()); } - /// @dev Returns whether royalty info can be set in the given execution context. + /// @dev Checks whether royalty info can be set in the given execution context. function _canSetRoyaltyInfo() internal view override returns (bool) { return hasRole(DEFAULT_ADMIN_ROLE, _msgSender()); } - /// @dev Returns whether contract metadata can be set in the given execution context. + /// @dev Checks whether contract metadata can be set in the given execution context. function _canSetContractURI() internal view override returns (bool) { return hasRole(DEFAULT_ADMIN_ROLE, _msgSender()); } - /// @dev Returns whether platform fee info can be set in the given execution context. + /// @dev Checks whether platform fee info can be set in the given execution context. function _canSetClaimConditions() internal view override returns (bool) { return hasRole(DEFAULT_ADMIN_ROLE, _msgSender()); } @@ -306,7 +341,7 @@ contract SignatureDrop is //////////////////////////////////////////////////////////////*/ /// @dev Burns `tokenId`. See {ERC721-_burn}. - function burn(uint256 tokenId) public virtual { + function burn(uint256 tokenId) external virtual { // note: ERC721AUpgradeable's `_burn(uint256,bool)` internally checks for token approvals. _burn(tokenId, true); } @@ -322,7 +357,9 @@ contract SignatureDrop is // if transfer is restricted on the contract, we still want to allow burning and minting if (!hasRole(TRANSFER_ROLE, address(0)) && from != address(0) && to != address(0)) { - require(hasRole(TRANSFER_ROLE, from) || hasRole(TRANSFER_ROLE, to), "!TRANSFER_ROLE"); + if (!hasRole(TRANSFER_ROLE, from) && !hasRole(TRANSFER_ROLE, to)) { + revert SignatureDrop__NotTransferRole(); + } } } diff --git a/docs/ContractMetadata.md b/docs/ContractMetadata.md index fb1e1fdec..e9ab0e6e3 100644 --- a/docs/ContractMetadata.md +++ b/docs/ContractMetadata.md @@ -4,7 +4,7 @@ - +Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI for you contract. Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea. @@ -66,3 +66,17 @@ event ContractURIUpdated(string prevURI, string newURI) +## Errors + +### ContractMetadata__NotAuthorized + +```solidity +error ContractMetadata__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set the contract metadata URI.* + + + diff --git a/docs/DelayedReveal.md b/docs/DelayedReveal.md index d682fe2fb..e5649e5ba 100644 --- a/docs/DelayedReveal.md +++ b/docs/DelayedReveal.md @@ -4,7 +4,7 @@ - +Thirdweb's `DelayedReveal` is a contract extension for base NFT contracts. It lets you create batches of 'delayed-reveal' NFTs. You can learn more about the usage of delayed reveal NFTs here - https://blog.thirdweb.com/delayed-reveal-nfts @@ -58,7 +58,7 @@ function encryptedBaseURI(uint256) external view returns (bytes) ### getRevealURI ```solidity -function getRevealURI(uint256 _batchId, bytes _key) external nonpayable returns (string revealedURI) +function getRevealURI(uint256 _batchId, bytes _key) external view returns (string revealedURI) ``` @@ -106,7 +106,7 @@ function isEncryptedBatch(uint256 _batchId) external view returns (bool) function reveal(uint256 identifier, bytes key) external nonpayable returns (string revealedURI) ``` - +Reveals a batch of delayed reveal NFTs. @@ -114,8 +114,8 @@ function reveal(uint256 identifier, bytes key) external nonpayable returns (stri | Name | Type | Description | |---|---|---| -| identifier | uint256 | undefined -| key | bytes | undefined +| identifier | uint256 | The ID for the batch of delayed-reveal NFTs to reveal. +| key | bytes | The key with which the base URI for the relevant batch of NFTs was encrypted. #### Returns @@ -126,3 +126,22 @@ function reveal(uint256 identifier, bytes key) external nonpayable returns (stri +## Errors + +### DelayedReveal__NothingToReveal + +```solidity +error DelayedReveal__NothingToReveal(uint256 batchId) +``` + +Emitted when encrypted URI for a given batch is empty. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| batchId | uint256 | undefined | + + diff --git a/docs/Drop.md b/docs/Drop.md index fb4a38684..a7dfebdeb 100644 --- a/docs/Drop.md +++ b/docs/Drop.md @@ -157,7 +157,7 @@ function getClaimTimestamp(uint256 _conditionId, address _claimer) external view function lazyMint(uint256 amount, string baseURIForTokens, bytes extraData) external nonpayable returns (uint256 batchId) ``` - +Lazy mints a given amount of NFTs. @@ -165,15 +165,15 @@ function lazyMint(uint256 amount, string baseURIForTokens, bytes extraData) exte | Name | Type | Description | |---|---|---| -| amount | uint256 | undefined -| baseURIForTokens | string | undefined -| extraData | bytes | undefined +| amount | uint256 | The number of NFTs to lazy mint. +| baseURIForTokens | string | The base URI for the 'n' number of NFTs being lazy minted, where the metadata for each of those NFTs is `${baseURIForTokens}/${tokenId}`. +| extraData | bytes | Additional bytes data to be used at the discretion of the consumer of the contract. #### Returns | Name | Type | Description | |---|---|---| -| batchId | uint256 | undefined +| batchId | uint256 | A unique integer identifier for the batch of NFTs lazy minted together. ### setClaimConditions @@ -281,3 +281,54 @@ event TokensClaimed(uint256 indexed claimConditionIndex, address indexed claimer +## Errors + +### LazyMint__InvalidIndex + +```solidity +error LazyMint__InvalidIndex(uint256 index) +``` + +Emitted when the given index is equal to or higher than total number of batches. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| index | uint256 | undefined | + +### LazyMint__NoBaseURIForToken + +```solidity +error LazyMint__NoBaseURIForToken(uint256 tokenId) +``` + +Emitted when there's no Base URI set for the given token ID. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| tokenId | uint256 | undefined | + +### LazyMint__NoBatchIDForToken + +```solidity +error LazyMint__NoBatchIDForToken(uint256 tokenId) +``` + +Emitted when the given token ID doesn't belong to any batch. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| tokenId | uint256 | undefined | + + diff --git a/docs/DropERC1155.md b/docs/DropERC1155.md index ff2b2d5fa..1386fa197 100644 --- a/docs/DropERC1155.md +++ b/docs/DropERC1155.md @@ -951,6 +951,23 @@ function setRoyaltyInfoForToken(uint256 _tokenId, address _recipient, uint256 _b | _recipient | address | undefined | _bps | uint256 | undefined +### setSaleRecipientForToken + +```solidity +function setSaleRecipientForToken(uint256 _tokenId, address _saleRecipient) external nonpayable +``` + + + +*Lets a contract admin set the recipient for all primary sales.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _tokenId | uint256 | undefined +| _saleRecipient | address | undefined + ### setWalletClaimCount ```solidity @@ -1167,7 +1184,7 @@ event ClaimConditionsUpdated(uint256 indexed tokenId, IDropClaimCondition.ClaimC ### DefaultRoyalty ```solidity -event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps) +event DefaultRoyalty(address indexed newRoyaltyRecipient, uint256 newRoyaltyBps) ``` @@ -1178,7 +1195,7 @@ event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps) | Name | Type | Description | |---|---|---| -| newRoyaltyRecipient | address | undefined | +| newRoyaltyRecipient `indexed` | address | undefined | | newRoyaltyBps | uint256 | undefined | ### MaxTotalSupplyUpdated @@ -1218,7 +1235,7 @@ event MaxWalletClaimCountUpdated(uint256 tokenId, uint256 count) ### OwnerUpdated ```solidity -event OwnerUpdated(address prevOwner, address newOwner) +event OwnerUpdated(address indexed prevOwner, address indexed newOwner) ``` @@ -1229,13 +1246,13 @@ event OwnerUpdated(address prevOwner, address newOwner) | Name | Type | Description | |---|---|---| -| prevOwner | address | undefined | -| newOwner | address | undefined | +| prevOwner `indexed` | address | undefined | +| newOwner `indexed` | address | undefined | ### PlatformFeeInfoUpdated ```solidity -event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBps) +event PlatformFeeInfoUpdated(address indexed platformFeeRecipient, uint256 platformFeeBps) ``` @@ -1246,7 +1263,7 @@ event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBp | Name | Type | Description | |---|---|---| -| platformFeeRecipient | address | undefined | +| platformFeeRecipient `indexed` | address | undefined | | platformFeeBps | uint256 | undefined | ### PrimarySaleRecipientUpdated @@ -1322,7 +1339,7 @@ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed ### RoyaltyForToken ```solidity -event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 royaltyBps) +event RoyaltyForToken(uint256 indexed tokenId, address indexed royaltyRecipient, uint256 royaltyBps) ``` @@ -1334,9 +1351,26 @@ event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 | Name | Type | Description | |---|---|---| | tokenId `indexed` | uint256 | undefined | -| royaltyRecipient | address | undefined | +| royaltyRecipient `indexed` | address | undefined | | royaltyBps | uint256 | undefined | +### SaleRecipientForTokenUpdated + +```solidity +event SaleRecipientForTokenUpdated(uint256 indexed tokenId, address saleRecipient) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| tokenId `indexed` | uint256 | undefined | +| saleRecipient | address | undefined | + ### TokensClaimed ```solidity @@ -1452,3 +1486,82 @@ event WalletClaimCountUpdated(uint256 tokenId, address indexed wallet, uint256 c +## Errors + +### Ownable__NotAuthorized + +```solidity +error Ownable__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set the owner.* + + +### PlatformFee__ExceedsMaxBps + +```solidity +error PlatformFee__ExceedsMaxBps(uint256 platformFeeBps) +``` + +Emitted when given platform-fee bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| platformFeeBps | uint256 | undefined | + +### PlatformFee__NotAuthorized + +```solidity +error PlatformFee__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set platform fee details.* + + +### PrimarySale__NotAuthorized + +```solidity +error PrimarySale__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set primary sales details.* + + +### Royalty__ExceedsMaxBps + +```solidity +error Royalty__ExceedsMaxBps(uint256 royaltyBps) +``` + +Emitted when the given bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| royaltyBps | uint256 | undefined | + +### Royalty__NotAuthorized + +```solidity +error Royalty__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set royalty details.* + + + diff --git a/docs/DropERC20.md b/docs/DropERC20.md index 2ff35eb39..30e91ec39 100644 --- a/docs/DropERC20.md +++ b/docs/DropERC20.md @@ -1267,7 +1267,7 @@ event MaxWalletClaimCountUpdated(uint256 count) ### PlatformFeeInfoUpdated ```solidity -event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBps) +event PlatformFeeInfoUpdated(address indexed platformFeeRecipient, uint256 platformFeeBps) ``` @@ -1278,7 +1278,7 @@ event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBp | Name | Type | Description | |---|---|---| -| platformFeeRecipient | address | undefined | +| platformFeeRecipient `indexed` | address | undefined | | platformFeeBps | uint256 | undefined | ### PrimarySaleRecipientUpdated @@ -1407,3 +1407,44 @@ event WalletClaimCountUpdated(address indexed wallet, uint256 count) +## Errors + +### PlatformFee__ExceedsMaxBps + +```solidity +error PlatformFee__ExceedsMaxBps(uint256 platformFeeBps) +``` + +Emitted when given platform-fee bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| platformFeeBps | uint256 | undefined | + +### PlatformFee__NotAuthorized + +```solidity +error PlatformFee__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set platform fee details.* + + +### PrimarySale__NotAuthorized + +```solidity +error PrimarySale__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set primary sales details.* + + + diff --git a/docs/DropERC721.md b/docs/DropERC721.md index b3abe591e..951bc3e40 100644 --- a/docs/DropERC721.md +++ b/docs/DropERC721.md @@ -1311,7 +1311,7 @@ event ClaimConditionsUpdated(IDropClaimCondition.ClaimCondition[] claimCondition ### DefaultRoyalty ```solidity -event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps) +event DefaultRoyalty(address indexed newRoyaltyRecipient, uint256 newRoyaltyBps) ``` @@ -1322,7 +1322,7 @@ event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps) | Name | Type | Description | |---|---|---| -| newRoyaltyRecipient | address | undefined | +| newRoyaltyRecipient `indexed` | address | undefined | | newRoyaltyBps | uint256 | undefined | ### MaxTotalSupplyUpdated @@ -1377,7 +1377,7 @@ event NFTRevealed(uint256 endTokenId, string revealedURI) ### OwnerUpdated ```solidity -event OwnerUpdated(address prevOwner, address newOwner) +event OwnerUpdated(address indexed prevOwner, address indexed newOwner) ``` @@ -1388,13 +1388,13 @@ event OwnerUpdated(address prevOwner, address newOwner) | Name | Type | Description | |---|---|---| -| prevOwner | address | undefined | -| newOwner | address | undefined | +| prevOwner `indexed` | address | undefined | +| newOwner `indexed` | address | undefined | ### PlatformFeeInfoUpdated ```solidity -event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBps) +event PlatformFeeInfoUpdated(address indexed platformFeeRecipient, uint256 platformFeeBps) ``` @@ -1405,7 +1405,7 @@ event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBp | Name | Type | Description | |---|---|---| -| platformFeeRecipient | address | undefined | +| platformFeeRecipient `indexed` | address | undefined | | platformFeeBps | uint256 | undefined | ### PrimarySaleRecipientUpdated @@ -1481,7 +1481,7 @@ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed ### RoyaltyForToken ```solidity -event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 royaltyBps) +event RoyaltyForToken(uint256 indexed tokenId, address indexed royaltyRecipient, uint256 royaltyBps) ``` @@ -1493,7 +1493,7 @@ event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 | Name | Type | Description | |---|---|---| | tokenId `indexed` | uint256 | undefined | -| royaltyRecipient | address | undefined | +| royaltyRecipient `indexed` | address | undefined | | royaltyBps | uint256 | undefined | ### TokensClaimed @@ -1572,3 +1572,82 @@ event WalletClaimCountUpdated(address indexed wallet, uint256 count) +## Errors + +### Ownable__NotAuthorized + +```solidity +error Ownable__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set the owner.* + + +### PlatformFee__ExceedsMaxBps + +```solidity +error PlatformFee__ExceedsMaxBps(uint256 platformFeeBps) +``` + +Emitted when given platform-fee bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| platformFeeBps | uint256 | undefined | + +### PlatformFee__NotAuthorized + +```solidity +error PlatformFee__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set platform fee details.* + + +### PrimarySale__NotAuthorized + +```solidity +error PrimarySale__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set primary sales details.* + + +### Royalty__ExceedsMaxBps + +```solidity +error Royalty__ExceedsMaxBps(uint256 royaltyBps) +``` + +Emitted when the given bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| royaltyBps | uint256 | undefined | + +### Royalty__NotAuthorized + +```solidity +error Royalty__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set royalty details.* + + + diff --git a/docs/DropSinglePhase.md b/docs/DropSinglePhase.md index 4077b211e..8b87e7577 100644 --- a/docs/DropSinglePhase.md +++ b/docs/DropSinglePhase.md @@ -13,7 +13,7 @@ ### claim ```solidity -function claim(address _receiver, uint256 _quantity, address _currency, uint256 _pricePerToken, IDrop.AllowlistProof _allowlistProof, bytes _data) external payable +function claim(address _receiver, uint256 _quantity, address _currency, uint256 _pricePerToken, IDropSinglePhase.AllowlistProof _allowlistProof, bytes _data) external payable ``` @@ -28,7 +28,7 @@ function claim(address _receiver, uint256 _quantity, address _currency, uint256 | _quantity | uint256 | undefined | _currency | address | undefined | _pricePerToken | uint256 | undefined -| _allowlistProof | IDrop.AllowlistProof | undefined +| _allowlistProof | IDropSinglePhase.AllowlistProof | undefined | _data | bytes | undefined ### claimCondition @@ -55,72 +55,99 @@ function claimCondition() external view returns (uint256 startTimestamp, uint256 | pricePerToken | uint256 | undefined | currency | address | undefined -### getBaseURICount +### getClaimTimestamp ```solidity -function getBaseURICount() external view returns (uint256) +function getClaimTimestamp(address _claimer) external view returns (uint256 lastClaimedAt, uint256 nextValidClaimTimestamp) ``` -*Returns the number of batches of tokens having the same baseURI.* +*Returns the timestamp for when a claimer is eligible for claiming NFTs again.* + +#### Parameters +| Name | Type | Description | +|---|---|---| +| _claimer | address | undefined #### Returns | Name | Type | Description | |---|---|---| -| _0 | uint256 | undefined +| lastClaimedAt | uint256 | undefined +| nextValidClaimTimestamp | uint256 | undefined -### getBatchIdAtIndex +### setClaimConditions ```solidity -function getBatchIdAtIndex(uint256 _index) external view returns (uint256) +function setClaimConditions(IClaimCondition.ClaimCondition _condition, bool _resetClaimEligibility) external nonpayable ``` -*Returns the id for the batch of tokens the given tokenId belongs to.* +*Lets a contract admin set claim conditions.* #### Parameters | Name | Type | Description | |---|---|---| -| _index | uint256 | undefined +| _condition | IClaimCondition.ClaimCondition | undefined +| _resetClaimEligibility | bool | undefined + +### verifyClaim + +```solidity +function verifyClaim(address _claimer, uint256 _quantity, address _currency, uint256 _pricePerToken, bool verifyMaxQuantityPerTransaction) external view +``` + -#### Returns + +*Checks a request to claim NFTs against the active claim condition's criteria.* + +#### Parameters | Name | Type | Description | |---|---|---| -| _0 | uint256 | undefined +| _claimer | address | undefined +| _quantity | uint256 | undefined +| _currency | address | undefined +| _pricePerToken | uint256 | undefined +| verifyMaxQuantityPerTransaction | bool | undefined -### getClaimTimestamp +### verifyClaimMerkleProof ```solidity -function getClaimTimestamp(address _claimer) external view returns (uint256 lastClaimedAt, uint256 nextValidClaimTimestamp) +function verifyClaimMerkleProof(address _claimer, uint256 _quantity, IDropSinglePhase.AllowlistProof _allowlistProof) external view returns (bool validMerkleProof, uint256 merkleProofIndex) ``` -*Returns the timestamp for when a claimer is eligible for claiming NFTs again.* +*Checks whether a claimer meets the claim condition's allowlist criteria.* #### Parameters | Name | Type | Description | |---|---|---| | _claimer | address | undefined +| _quantity | uint256 | undefined +| _allowlistProof | IDropSinglePhase.AllowlistProof | undefined #### Returns | Name | Type | Description | |---|---|---| -| lastClaimedAt | uint256 | undefined -| nextValidClaimTimestamp | uint256 | undefined +| validMerkleProof | bool | undefined +| merkleProofIndex | uint256 | undefined + + + +## Events -### lazyMint +### ClaimConditionUpdated ```solidity -function lazyMint(uint256 amount, string baseURIForTokens, bytes extraData) external nonpayable returns (uint256 batchId) +event ClaimConditionUpdated(IClaimCondition.ClaimCondition condition, bool resetEligibility) ``` @@ -131,89 +158,105 @@ function lazyMint(uint256 amount, string baseURIForTokens, bytes extraData) exte | Name | Type | Description | |---|---|---| -| amount | uint256 | undefined -| baseURIForTokens | string | undefined -| extraData | bytes | undefined +| condition | IClaimCondition.ClaimCondition | undefined | +| resetEligibility | bool | undefined | + +### TokensClaimed + +```solidity +event TokensClaimed(address indexed claimer, address indexed receiver, uint256 indexed startTokenId, uint256 quantityClaimed) +``` -#### Returns + + + + +#### Parameters | Name | Type | Description | |---|---|---| -| batchId | uint256 | undefined +| claimer `indexed` | address | undefined | +| receiver `indexed` | address | undefined | +| startTokenId `indexed` | uint256 | undefined | +| quantityClaimed | uint256 | undefined | -### setClaimConditions + + +## Errors + +### DropSinglePhase__CannotClaimYet ```solidity -function setClaimConditions(IClaimCondition.ClaimCondition _condition, bool _resetClaimEligibility) external nonpayable +error DropSinglePhase__CannotClaimYet(uint256 blockTimestamp, uint256 startTimestamp, uint256 lastClaimedAt, uint256 nextValidClaimTimestamp) ``` +Emitted when the current timestamp is invalid for claim. -*Lets a contract admin set claim conditions.* #### Parameters | Name | Type | Description | |---|---|---| -| _condition | IClaimCondition.ClaimCondition | undefined -| _resetClaimEligibility | bool | undefined +| blockTimestamp | uint256 | undefined | +| startTimestamp | uint256 | undefined | +| lastClaimedAt | uint256 | undefined | +| nextValidClaimTimestamp | uint256 | undefined | -### verifyClaim +### DropSinglePhase__ExceedMaxClaimableSupply ```solidity -function verifyClaim(address _claimer, uint256 _quantity, address _currency, uint256 _pricePerToken, bool verifyMaxQuantityPerTransaction) external view +error DropSinglePhase__ExceedMaxClaimableSupply(uint256 supplyClaimed, uint256 maxClaimableSupply) ``` +Emitted when claiming given quantity will exceed max claimable supply. -*Checks a request to claim NFTs against the active claim condition's criteria.* #### Parameters | Name | Type | Description | |---|---|---| -| _claimer | address | undefined -| _quantity | uint256 | undefined -| _currency | address | undefined -| _pricePerToken | uint256 | undefined -| verifyMaxQuantityPerTransaction | bool | undefined +| supplyClaimed | uint256 | undefined | +| maxClaimableSupply | uint256 | undefined | -### verifyClaimMerkleProof +### DropSinglePhase__InvalidCurrencyOrPrice ```solidity -function verifyClaimMerkleProof(address _claimer, uint256 _quantity, IDrop.AllowlistProof _allowlistProof) external view returns (bool validMerkleProof, uint256 merkleProofIndex) +error DropSinglePhase__InvalidCurrencyOrPrice(address givenCurrency, address requiredCurrency, uint256 givenPricePerToken, uint256 requiredPricePerToken) ``` +Emitted when given currency or price is invalid. -*Checks whether a claimer meets the claim condition's allowlist criteria.* #### Parameters | Name | Type | Description | |---|---|---| -| _claimer | address | undefined -| _quantity | uint256 | undefined -| _allowlistProof | IDrop.AllowlistProof | undefined +| givenCurrency | address | undefined | +| requiredCurrency | address | undefined | +| givenPricePerToken | uint256 | undefined | +| requiredPricePerToken | uint256 | undefined | -#### Returns +### DropSinglePhase__InvalidQuantity -| Name | Type | Description | -|---|---|---| -| validMerkleProof | bool | undefined -| merkleProofIndex | uint256 | undefined +```solidity +error DropSinglePhase__InvalidQuantity() +``` +Emitted when claiming invalid quantity of tokens. -## Events -### ClaimConditionUpdated + +### DropSinglePhase__InvalidQuantityProof ```solidity -event ClaimConditionUpdated(IClaimCondition.ClaimCondition claimConditions, bool resetClaimEligibility) +error DropSinglePhase__InvalidQuantityProof(uint256 maxQuantityInAllowlist) ``` - +Emitted when claiming more than allowed quantity in allowlist. @@ -221,16 +264,15 @@ event ClaimConditionUpdated(IClaimCondition.ClaimCondition claimConditions, bool | Name | Type | Description | |---|---|---| -| claimConditions | IClaimCondition.ClaimCondition | undefined | -| resetClaimEligibility | bool | undefined | +| maxQuantityInAllowlist | uint256 | undefined | -### TokensClaimed +### DropSinglePhase__MaxSupplyClaimedAlready ```solidity -event TokensClaimed(uint256 indexed claimConditionIndex, address indexed claimer, address indexed receiver, uint256 startTokenId, uint256 quantityClaimed) +error DropSinglePhase__MaxSupplyClaimedAlready(uint256 supplyClaimedAlready) ``` - +Emitted when max claimable supply in given condition is less than supply claimed already. @@ -238,11 +280,39 @@ event TokensClaimed(uint256 indexed claimConditionIndex, address indexed claimer | Name | Type | Description | |---|---|---| -| claimConditionIndex `indexed` | uint256 | undefined | -| claimer `indexed` | address | undefined | -| receiver `indexed` | address | undefined | -| startTokenId | uint256 | undefined | -| quantityClaimed | uint256 | undefined | +| supplyClaimedAlready | uint256 | undefined | + +### DropSinglePhase__NotAuthorized + +```solidity +error DropSinglePhase__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set claim conditions.* + + +### DropSinglePhase__NotInWhitelist + +```solidity +error DropSinglePhase__NotInWhitelist() +``` + +Emitted when given allowlist proof is invalid. + + + + +### DropSinglePhase__ProofClaimed + +```solidity +error DropSinglePhase__ProofClaimed() +``` + +Emitted when allowlist spot is already used. + + diff --git a/docs/IContractMetadata.md b/docs/IContractMetadata.md index 720d81fcc..b5c1efdbf 100644 --- a/docs/IContractMetadata.md +++ b/docs/IContractMetadata.md @@ -4,7 +4,7 @@ - +Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI for you contract. Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea. @@ -55,7 +55,7 @@ event ContractURIUpdated(string prevURI, string newURI) - +*Emitted when the contract URI is updated.* #### Parameters @@ -66,3 +66,17 @@ event ContractURIUpdated(string prevURI, string newURI) +## Errors + +### ContractMetadata__NotAuthorized + +```solidity +error ContractMetadata__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set the contract metadata URI.* + + + diff --git a/docs/IDelayedReveal.md b/docs/IDelayedReveal.md index 78027e2fd..43a108e6c 100644 --- a/docs/IDelayedReveal.md +++ b/docs/IDelayedReveal.md @@ -4,7 +4,7 @@ - +Thirdweb's `DelayedReveal` is a contract extension for base NFT contracts. It lets you create batches of 'delayed-reveal' NFTs. You can learn more about the usage of delayed reveal NFTs here - https://blog.thirdweb.com/delayed-reveal-nfts @@ -16,7 +16,7 @@ function encryptDecrypt(bytes data, bytes key) external pure returns (bytes result) ``` - +Performs XOR encryption/decryption. @@ -24,8 +24,8 @@ function encryptDecrypt(bytes data, bytes key) external pure returns (bytes resu | Name | Type | Description | |---|---|---| -| data | bytes | undefined -| key | bytes | undefined +| data | bytes | The data to encrypt. In the case of delayed-reveal NFTs, this is the "revealed" state base URI of the relevant batch of NFTs. +| key | bytes | The key with which to encrypt data #### Returns @@ -39,7 +39,7 @@ function encryptDecrypt(bytes data, bytes key) external pure returns (bytes resu function reveal(uint256 identifier, bytes key) external nonpayable returns (string revealedURI) ``` - +Reveals a batch of delayed reveal NFTs. @@ -47,8 +47,8 @@ function reveal(uint256 identifier, bytes key) external nonpayable returns (stri | Name | Type | Description | |---|---|---| -| identifier | uint256 | undefined -| key | bytes | undefined +| identifier | uint256 | The ID for the batch of delayed-reveal NFTs to reveal. +| key | bytes | The key with which the base URI for the relevant batch of NFTs was encrypted. #### Returns @@ -59,3 +59,22 @@ function reveal(uint256 identifier, bytes key) external nonpayable returns (stri +## Errors + +### DelayedReveal__NothingToReveal + +```solidity +error DelayedReveal__NothingToReveal(uint256 batchId) +``` + +Emitted when encrypted URI for a given batch is empty. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| batchId | uint256 | undefined | + + diff --git a/docs/IDrop.md b/docs/IDrop.md index ce80af768..502a0dcdb 100644 --- a/docs/IDrop.md +++ b/docs/IDrop.md @@ -37,7 +37,7 @@ Lets an account claim a given quantity of NFTs. function lazyMint(uint256 amount, string baseURIForTokens, bytes extraData) external nonpayable returns (uint256 batchId) ``` - +Lazy mints a given amount of NFTs. @@ -45,15 +45,15 @@ function lazyMint(uint256 amount, string baseURIForTokens, bytes extraData) exte | Name | Type | Description | |---|---|---| -| amount | uint256 | undefined -| baseURIForTokens | string | undefined -| extraData | bytes | undefined +| amount | uint256 | The number of NFTs to lazy mint. +| baseURIForTokens | string | The base URI for the 'n' number of NFTs being lazy minted, where the metadata for each of those NFTs is `${baseURIForTokens}/${tokenId}`. +| extraData | bytes | Additional bytes data to be used at the discretion of the consumer of the contract. #### Returns | Name | Type | Description | |---|---|---| -| batchId | uint256 | undefined +| batchId | uint256 | A unique integer identifier for the batch of NFTs lazy minted together. @@ -81,3 +81,54 @@ event TokensClaimed(uint256 indexed claimConditionIndex, address indexed claimer +## Errors + +### LazyMint__InvalidIndex + +```solidity +error LazyMint__InvalidIndex(uint256 index) +``` + +Emitted when the given index is equal to or higher than total number of batches. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| index | uint256 | undefined | + +### LazyMint__NoBaseURIForToken + +```solidity +error LazyMint__NoBaseURIForToken(uint256 tokenId) +``` + +Emitted when there's no Base URI set for the given token ID. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| tokenId | uint256 | undefined | + +### LazyMint__NoBatchIDForToken + +```solidity +error LazyMint__NoBatchIDForToken(uint256 tokenId) +``` + +Emitted when the given token ID doesn't belong to any batch. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| tokenId | uint256 | undefined | + + diff --git a/docs/IDropERC1155.md b/docs/IDropERC1155.md index e3fbe1642..0d19f09f4 100644 --- a/docs/IDropERC1155.md +++ b/docs/IDropERC1155.md @@ -288,6 +288,23 @@ event MaxWalletClaimCountUpdated(uint256 tokenId, uint256 count) | tokenId | uint256 | undefined | | count | uint256 | undefined | +### SaleRecipientForTokenUpdated + +```solidity +event SaleRecipientForTokenUpdated(uint256 indexed tokenId, address saleRecipient) +``` + + + +*Emitted when the sale recipient for a particular tokenId is updated.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| tokenId `indexed` | uint256 | undefined | +| saleRecipient | address | undefined | + ### TokensClaimed ```solidity diff --git a/docs/IDropSinglePhase.md b/docs/IDropSinglePhase.md new file mode 100644 index 000000000..972e9ca7d --- /dev/null +++ b/docs/IDropSinglePhase.md @@ -0,0 +1,226 @@ +# IDropSinglePhase + + + + + + + + + +## Methods + +### claim + +```solidity +function claim(address receiver, uint256 quantity, address currency, uint256 pricePerToken, IDropSinglePhase.AllowlistProof allowlistProof, bytes data) external payable +``` + +Lets an account claim a given quantity of NFTs. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| receiver | address | The receiver of the NFTs to claim. +| quantity | uint256 | The quantity of NFTs to claim. +| currency | address | The currency in which to pay for the claim. +| pricePerToken | uint256 | The price per token to pay for the claim. +| allowlistProof | IDropSinglePhase.AllowlistProof | The proof of the claimer's inclusion in the merkle root allowlist of the claim conditions that apply. +| data | bytes | Arbitrary bytes data that can be leveraged in the implementation of this interface. + +### setClaimConditions + +```solidity +function setClaimConditions(IClaimCondition.ClaimCondition phase, bool resetClaimEligibility) external nonpayable +``` + +Lets a contract admin (account with `DEFAULT_ADMIN_ROLE`) set claim conditions. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| phase | IClaimCondition.ClaimCondition | Claim condition to set. +| resetClaimEligibility | bool | Whether to reset `limitLastClaimTimestamp` and `limitMerkleProofClaim` values when setting new claim conditions. + + + +## Events + +### ClaimConditionUpdated + +```solidity +event ClaimConditionUpdated(IClaimCondition.ClaimCondition condition, bool resetEligibility) +``` + + + +*Emitted when the contract's claim conditions are updated.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| condition | IClaimCondition.ClaimCondition | undefined | +| resetEligibility | bool | undefined | + +### TokensClaimed + +```solidity +event TokensClaimed(address indexed claimer, address indexed receiver, uint256 indexed startTokenId, uint256 quantityClaimed) +``` + + + +*Emitted when tokens are claimed via `claim`.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| claimer `indexed` | address | undefined | +| receiver `indexed` | address | undefined | +| startTokenId `indexed` | uint256 | undefined | +| quantityClaimed | uint256 | undefined | + + + +## Errors + +### DropSinglePhase__CannotClaimYet + +```solidity +error DropSinglePhase__CannotClaimYet(uint256 blockTimestamp, uint256 startTimestamp, uint256 lastClaimedAt, uint256 nextValidClaimTimestamp) +``` + +Emitted when the current timestamp is invalid for claim. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| blockTimestamp | uint256 | undefined | +| startTimestamp | uint256 | undefined | +| lastClaimedAt | uint256 | undefined | +| nextValidClaimTimestamp | uint256 | undefined | + +### DropSinglePhase__ExceedMaxClaimableSupply + +```solidity +error DropSinglePhase__ExceedMaxClaimableSupply(uint256 supplyClaimed, uint256 maxClaimableSupply) +``` + +Emitted when claiming given quantity will exceed max claimable supply. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| supplyClaimed | uint256 | undefined | +| maxClaimableSupply | uint256 | undefined | + +### DropSinglePhase__InvalidCurrencyOrPrice + +```solidity +error DropSinglePhase__InvalidCurrencyOrPrice(address givenCurrency, address requiredCurrency, uint256 givenPricePerToken, uint256 requiredPricePerToken) +``` + +Emitted when given currency or price is invalid. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| givenCurrency | address | undefined | +| requiredCurrency | address | undefined | +| givenPricePerToken | uint256 | undefined | +| requiredPricePerToken | uint256 | undefined | + +### DropSinglePhase__InvalidQuantity + +```solidity +error DropSinglePhase__InvalidQuantity() +``` + +Emitted when claiming invalid quantity of tokens. + + + + +### DropSinglePhase__InvalidQuantityProof + +```solidity +error DropSinglePhase__InvalidQuantityProof(uint256 maxQuantityInAllowlist) +``` + +Emitted when claiming more than allowed quantity in allowlist. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| maxQuantityInAllowlist | uint256 | undefined | + +### DropSinglePhase__MaxSupplyClaimedAlready + +```solidity +error DropSinglePhase__MaxSupplyClaimedAlready(uint256 supplyClaimedAlready) +``` + +Emitted when max claimable supply in given condition is less than supply claimed already. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| supplyClaimedAlready | uint256 | undefined | + +### DropSinglePhase__NotAuthorized + +```solidity +error DropSinglePhase__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set claim conditions.* + + +### DropSinglePhase__NotInWhitelist + +```solidity +error DropSinglePhase__NotInWhitelist() +``` + +Emitted when given allowlist proof is invalid. + + + + +### DropSinglePhase__ProofClaimed + +```solidity +error DropSinglePhase__ProofClaimed() +``` + +Emitted when allowlist spot is already used. + + + + + diff --git a/docs/ILazyMint.md b/docs/ILazyMint.md index de1b76b89..9c598098c 100644 --- a/docs/ILazyMint.md +++ b/docs/ILazyMint.md @@ -4,7 +4,7 @@ - +Thirdweb's `LazyMint` is a contract extension for any base NFT contract. It lets you 'lazy mint' any number of NFTs at once. Here, 'lazy mint' means defining the metadata for particular tokenIds of your NFT contract, without actually minting a non-zero balance of NFTs of those tokenIds. @@ -16,7 +16,7 @@ function lazyMint(uint256 amount, string baseURIForTokens, bytes extraData) external nonpayable returns (uint256 batchId) ``` - +Lazy mints a given amount of NFTs. @@ -24,16 +24,67 @@ function lazyMint(uint256 amount, string baseURIForTokens, bytes extraData) exte | Name | Type | Description | |---|---|---| -| amount | uint256 | undefined -| baseURIForTokens | string | undefined -| extraData | bytes | undefined +| amount | uint256 | The number of NFTs to lazy mint. +| baseURIForTokens | string | The base URI for the 'n' number of NFTs being lazy minted, where the metadata for each of those NFTs is `${baseURIForTokens}/${tokenId}`. +| extraData | bytes | Additional bytes data to be used at the discretion of the consumer of the contract. #### Returns | Name | Type | Description | |---|---|---| -| batchId | uint256 | undefined +| batchId | uint256 | A unique integer identifier for the batch of NFTs lazy minted together. + + + + +## Errors + +### LazyMint__InvalidIndex + +```solidity +error LazyMint__InvalidIndex(uint256 index) +``` + +Emitted when the given index is equal to or higher than total number of batches. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| index | uint256 | undefined | + +### LazyMint__NoBaseURIForToken + +```solidity +error LazyMint__NoBaseURIForToken(uint256 tokenId) +``` + +Emitted when there's no Base URI set for the given token ID. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| tokenId | uint256 | undefined | +### LazyMint__NoBatchIDForToken +```solidity +error LazyMint__NoBatchIDForToken(uint256 tokenId) +``` + +Emitted when the given token ID doesn't belong to any batch. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| tokenId | uint256 | undefined | diff --git a/docs/IMarketplace.md b/docs/IMarketplace.md index ecd04d5c7..1e3bb0f94 100644 --- a/docs/IMarketplace.md +++ b/docs/IMarketplace.md @@ -381,7 +381,7 @@ event NewSale(uint256 indexed listingId, address indexed assetContract, address ### PlatformFeeInfoUpdated ```solidity -event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBps) +event PlatformFeeInfoUpdated(address indexed platformFeeRecipient, uint256 platformFeeBps) ``` @@ -392,8 +392,38 @@ event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBp | Name | Type | Description | |---|---|---| -| platformFeeRecipient | address | undefined | +| platformFeeRecipient `indexed` | address | undefined | | platformFeeBps | uint256 | undefined | +## Errors + +### PlatformFee__ExceedsMaxBps + +```solidity +error PlatformFee__ExceedsMaxBps(uint256 platformFeeBps) +``` + +Emitted when given platform-fee bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| platformFeeBps | uint256 | undefined | + +### PlatformFee__NotAuthorized + +```solidity +error PlatformFee__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set platform fee details.* + + + diff --git a/docs/IOwnable.md b/docs/IOwnable.md index 7539d99c9..9c50c9663 100644 --- a/docs/IOwnable.md +++ b/docs/IOwnable.md @@ -4,7 +4,7 @@ - +Thirdweb's `Ownable` is a contract extension to be used with any base contract. It exposes functions for setting and reading who the 'owner' of the inheriting smart contract is, and lets the inheriting contract perform conditional logic that uses information about who the contract's owner is. @@ -50,7 +50,7 @@ function setOwner(address _newOwner) external nonpayable ### OwnerUpdated ```solidity -event OwnerUpdated(address prevOwner, address newOwner) +event OwnerUpdated(address indexed prevOwner, address indexed newOwner) ``` @@ -61,8 +61,22 @@ event OwnerUpdated(address prevOwner, address newOwner) | Name | Type | Description | |---|---|---| -| prevOwner | address | undefined | -| newOwner | address | undefined | +| prevOwner `indexed` | address | undefined | +| newOwner `indexed` | address | undefined | + + + +## Errors + +### Ownable__NotAuthorized + +```solidity +error Ownable__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set the owner.* diff --git a/docs/IPermissions.md b/docs/IPermissions.md index 3156847c8..50a5a426a 100644 --- a/docs/IPermissions.md +++ b/docs/IPermissions.md @@ -72,6 +72,29 @@ function hasRole(bytes32 role, address account) external view returns (bool) |---|---|---| | _0 | bool | undefined +### hasRoleWithSwitch + +```solidity +function hasRoleWithSwitch(bytes32 role, address account) external view returns (bool) +``` + + + +*Returns `true` if either (1) `account` has been granted `role`, or (2) the relevant role restrictions do not apply at the time of calling this function.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined +| account | address | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bool | undefined + ### renounceRole ```solidity @@ -166,3 +189,39 @@ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed +## Errors + +### Permissions__CanOnlyGrantToNonHolders + +```solidity +error Permissions__CanOnlyGrantToNonHolders(address account) +``` + +Emitted when specified account already has the role. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| account | address | undefined | + +### Permissions__CanOnlyRenounceForSelf + +```solidity +error Permissions__CanOnlyRenounceForSelf(address caller, address account) +``` + +Emitted when calling address is different from the specified account. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| caller | address | undefined | +| account | address | undefined | + + diff --git a/docs/IPermissionsEnumerable.md b/docs/IPermissionsEnumerable.md index aba66bbfb..50bba4a37 100644 --- a/docs/IPermissionsEnumerable.md +++ b/docs/IPermissionsEnumerable.md @@ -117,6 +117,29 @@ function hasRole(bytes32 role, address account) external view returns (bool) |---|---|---| | _0 | bool | undefined +### hasRoleWithSwitch + +```solidity +function hasRoleWithSwitch(bytes32 role, address account) external view returns (bool) +``` + + + +*Returns `true` if either (1) `account` has been granted `role`, or (2) the relevant role restrictions do not apply at the time of calling this function.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined +| account | address | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bool | undefined + ### renounceRole ```solidity @@ -211,3 +234,39 @@ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed +## Errors + +### Permissions__CanOnlyGrantToNonHolders + +```solidity +error Permissions__CanOnlyGrantToNonHolders(address account) +``` + +Emitted when specified account already has the role. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| account | address | undefined | + +### Permissions__CanOnlyRenounceForSelf + +```solidity +error Permissions__CanOnlyRenounceForSelf(address caller, address account) +``` + +Emitted when calling address is different from the specified account. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| caller | address | undefined | +| account | address | undefined | + + diff --git a/docs/IPlatformFee.md b/docs/IPlatformFee.md index 7568c4b76..e68b30a62 100644 --- a/docs/IPlatformFee.md +++ b/docs/IPlatformFee.md @@ -4,7 +4,7 @@ - +Thirdweb's `PlatformFee` is a contract extension to be used with any base contract. It exposes functions for setting and reading the recipient of platform fee and the platform fee basis points, and lets the inheriting contract perform conditional logic that uses information about platform fees, if desired. @@ -52,7 +52,7 @@ function setPlatformFeeInfo(address _platformFeeRecipient, uint256 _platformFeeB ### PlatformFeeInfoUpdated ```solidity -event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBps) +event PlatformFeeInfoUpdated(address indexed platformFeeRecipient, uint256 platformFeeBps) ``` @@ -63,8 +63,38 @@ event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBp | Name | Type | Description | |---|---|---| -| platformFeeRecipient | address | undefined | +| platformFeeRecipient `indexed` | address | undefined | | platformFeeBps | uint256 | undefined | +## Errors + +### PlatformFee__ExceedsMaxBps + +```solidity +error PlatformFee__ExceedsMaxBps(uint256 platformFeeBps) +``` + +Emitted when given platform-fee bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| platformFeeBps | uint256 | undefined | + +### PlatformFee__NotAuthorized + +```solidity +error PlatformFee__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set platform fee details.* + + + diff --git a/docs/IPrimarySale.md b/docs/IPrimarySale.md index 5d8bd2075..d8cabf4d0 100644 --- a/docs/IPrimarySale.md +++ b/docs/IPrimarySale.md @@ -4,7 +4,7 @@ - +Thirdweb's `Primary` is a contract extension to be used with any base contract. It exposes functions for setting and reading the recipient of primary sales, and lets the inheriting contract perform conditional logic that uses information about primary sales, if desired. @@ -65,3 +65,17 @@ event PrimarySaleRecipientUpdated(address indexed recipient) +## Errors + +### PrimarySale__NotAuthorized + +```solidity +error PrimarySale__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set primary sales details.* + + + diff --git a/docs/IRoyalty.md b/docs/IRoyalty.md index b781dd20e..ac9203755 100644 --- a/docs/IRoyalty.md +++ b/docs/IRoyalty.md @@ -4,7 +4,7 @@ - +Thirdweb's `Royalty` is a contract extension to be used with any base contract. It exposes functions for setting and reading the recipient of royalty fee and the royalty fee basis points, and lets the inheriting contract perform conditional logic that uses information about royalty fees, if desired. The `Royalty` contract is ERC2981 compliant. @@ -117,7 +117,7 @@ function setRoyaltyInfoForToken(uint256 tokenId, address recipient, uint256 bps) ### DefaultRoyalty ```solidity -event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps) +event DefaultRoyalty(address indexed newRoyaltyRecipient, uint256 newRoyaltyBps) ``` @@ -128,13 +128,13 @@ event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps) | Name | Type | Description | |---|---|---| -| newRoyaltyRecipient | address | undefined | +| newRoyaltyRecipient `indexed` | address | undefined | | newRoyaltyBps | uint256 | undefined | ### RoyaltyForToken ```solidity -event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 royaltyBps) +event RoyaltyForToken(uint256 indexed tokenId, address indexed royaltyRecipient, uint256 royaltyBps) ``` @@ -146,8 +146,38 @@ event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 | Name | Type | Description | |---|---|---| | tokenId `indexed` | uint256 | undefined | -| royaltyRecipient | address | undefined | +| royaltyRecipient `indexed` | address | undefined | | royaltyBps | uint256 | undefined | +## Errors + +### Royalty__ExceedsMaxBps + +```solidity +error Royalty__ExceedsMaxBps(uint256 royaltyBps) +``` + +Emitted when the given bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| royaltyBps | uint256 | undefined | + +### Royalty__NotAuthorized + +```solidity +error Royalty__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set royalty details.* + + + diff --git a/docs/ISignatureMintERC721.md b/docs/ISignatureMintERC721.md index 74e612f7f..3e0e0d041 100644 --- a/docs/ISignatureMintERC721.md +++ b/docs/ISignatureMintERC721.md @@ -82,3 +82,33 @@ event TokensMintedWithSignature(address indexed signer, address indexed mintedTo +## Errors + +### SignatureMintERC721__InvalidRequest + +```solidity +error SignatureMintERC721__InvalidRequest() +``` + +Emitted when either the signature or the request uid is invalid. + + + + +### SignatureMintERC721__RequestExpired + +```solidity +error SignatureMintERC721__RequestExpired(uint256 blockTimestamp) +``` + +Emitted when block-timestamp is outside of validity start and end range. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| blockTimestamp | uint256 | undefined | + + diff --git a/docs/LazyMint.md b/docs/LazyMint.md index f9fe22cd8..7d8f88b73 100644 --- a/docs/LazyMint.md +++ b/docs/LazyMint.md @@ -4,7 +4,7 @@ - +Thirdweb's `LazyMint` is a contract extension for any base NFT contract. It lets you 'lazy mint' any number of NFTs at once. Here, 'lazy mint' means defining the metadata for particular tokenIds of your NFT contract, without actually minting a non-zero balance of NFTs of those tokenIds. @@ -55,7 +55,7 @@ function getBatchIdAtIndex(uint256 _index) external view returns (uint256) function lazyMint(uint256 amount, string baseURIForTokens, bytes extraData) external nonpayable returns (uint256 batchId) ``` - +Lazy mints a given amount of NFTs. @@ -63,16 +63,67 @@ function lazyMint(uint256 amount, string baseURIForTokens, bytes extraData) exte | Name | Type | Description | |---|---|---| -| amount | uint256 | undefined -| baseURIForTokens | string | undefined -| extraData | bytes | undefined +| amount | uint256 | The number of NFTs to lazy mint. +| baseURIForTokens | string | The base URI for the 'n' number of NFTs being lazy minted, where the metadata for each of those NFTs is `${baseURIForTokens}/${tokenId}`. +| extraData | bytes | Additional bytes data to be used at the discretion of the consumer of the contract. #### Returns | Name | Type | Description | |---|---|---| -| batchId | uint256 | undefined +| batchId | uint256 | A unique integer identifier for the batch of NFTs lazy minted together. + + + + +## Errors + +### LazyMint__InvalidIndex + +```solidity +error LazyMint__InvalidIndex(uint256 index) +``` + +Emitted when the given index is equal to or higher than total number of batches. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| index | uint256 | undefined | + +### LazyMint__NoBaseURIForToken + +```solidity +error LazyMint__NoBaseURIForToken(uint256 tokenId) +``` + +Emitted when there's no Base URI set for the given token ID. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| tokenId | uint256 | undefined | +### LazyMint__NoBatchIDForToken +```solidity +error LazyMint__NoBatchIDForToken(uint256 tokenId) +``` + +Emitted when the given token ID doesn't belong to any batch. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| tokenId | uint256 | undefined | diff --git a/docs/LazyMintERC721.md b/docs/LazyMintERC721.md index b08cba43e..77139961b 100644 --- a/docs/LazyMintERC721.md +++ b/docs/LazyMintERC721.md @@ -119,7 +119,7 @@ function tokenURI(uint256 _tokenId) external view returns (string) ### TokensLazyMinted ```solidity -event TokensLazyMinted(uint256 startTokenId, uint256 endTokenId, string baseURI, bytes extraData) +event TokensLazyMinted(uint256 indexed startTokenId, uint256 endTokenId, string baseURI, bytes extraData) ``` @@ -130,10 +130,61 @@ event TokensLazyMinted(uint256 startTokenId, uint256 endTokenId, string baseURI, | Name | Type | Description | |---|---|---| -| startTokenId | uint256 | undefined | +| startTokenId `indexed` | uint256 | undefined | | endTokenId | uint256 | undefined | | baseURI | string | undefined | | extraData | bytes | undefined | +## Errors + +### LazyMint__InvalidIndex + +```solidity +error LazyMint__InvalidIndex(uint256 index) +``` + +Emitted when the given index is equal to or higher than total number of batches. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| index | uint256 | undefined | + +### LazyMint__NoBaseURIForToken + +```solidity +error LazyMint__NoBaseURIForToken(uint256 tokenId) +``` + +Emitted when there's no Base URI set for the given token ID. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| tokenId | uint256 | undefined | + +### LazyMint__NoBatchIDForToken + +```solidity +error LazyMint__NoBatchIDForToken(uint256 tokenId) +``` + +Emitted when the given token ID doesn't belong to any batch. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| tokenId | uint256 | undefined | + + diff --git a/docs/Marketplace.md b/docs/Marketplace.md index 13ba8652e..8f598675b 100644 --- a/docs/Marketplace.md +++ b/docs/Marketplace.md @@ -892,7 +892,7 @@ event NewSale(uint256 indexed listingId, address indexed assetContract, address ### PlatformFeeInfoUpdated ```solidity -event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBps) +event PlatformFeeInfoUpdated(address indexed platformFeeRecipient, uint256 platformFeeBps) ``` @@ -903,7 +903,7 @@ event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBp | Name | Type | Description | |---|---|---| -| platformFeeRecipient | address | undefined | +| platformFeeRecipient `indexed` | address | undefined | | platformFeeBps | uint256 | undefined | ### RoleAdminChanged @@ -962,3 +962,33 @@ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed +## Errors + +### PlatformFee__ExceedsMaxBps + +```solidity +error PlatformFee__ExceedsMaxBps(uint256 platformFeeBps) +``` + +Emitted when given platform-fee bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| platformFeeBps | uint256 | undefined | + +### PlatformFee__NotAuthorized + +```solidity +error PlatformFee__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set platform fee details.* + + + diff --git a/docs/Multiwrap.md b/docs/Multiwrap.md index 5a47e3747..06f1685fc 100644 --- a/docs/Multiwrap.md +++ b/docs/Multiwrap.md @@ -361,7 +361,7 @@ function grantRole(bytes32 role, address account) external nonpayable - +*Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.* #### Parameters @@ -401,7 +401,7 @@ function hasRoleWithSwitch(bytes32 role, address account) external view returns - +*Returns `true` if either (1) `account` has been granted `role`, or (2) the relevant role restrictions do not apply at the time of calling this function.* #### Parameters @@ -663,7 +663,7 @@ function renounceRole(bytes32 role, address account) external nonpayable - +*Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`.* #### Parameters @@ -680,7 +680,7 @@ function revokeRole(bytes32 role, address account) external nonpayable - +*Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.* #### Parameters @@ -996,7 +996,7 @@ event ContractURIUpdated(string prevURI, string newURI) ### DefaultRoyalty ```solidity -event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps) +event DefaultRoyalty(address indexed newRoyaltyRecipient, uint256 newRoyaltyBps) ``` @@ -1007,13 +1007,13 @@ event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps) | Name | Type | Description | |---|---|---| -| newRoyaltyRecipient | address | undefined | +| newRoyaltyRecipient `indexed` | address | undefined | | newRoyaltyBps | uint256 | undefined | ### OwnerUpdated ```solidity -event OwnerUpdated(address prevOwner, address newOwner) +event OwnerUpdated(address indexed prevOwner, address indexed newOwner) ``` @@ -1024,8 +1024,8 @@ event OwnerUpdated(address prevOwner, address newOwner) | Name | Type | Description | |---|---|---| -| prevOwner | address | undefined | -| newOwner | address | undefined | +| prevOwner `indexed` | address | undefined | +| newOwner `indexed` | address | undefined | ### RoleAdminChanged @@ -1084,7 +1084,7 @@ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed ### RoyaltyForToken ```solidity -event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 royaltyBps) +event RoyaltyForToken(uint256 indexed tokenId, address indexed royaltyRecipient, uint256 royaltyBps) ``` @@ -1096,7 +1096,7 @@ event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 | Name | Type | Description | |---|---|---| | tokenId `indexed` | uint256 | undefined | -| royaltyRecipient | address | undefined | +| royaltyRecipient `indexed` | address | undefined | | royaltyBps | uint256 | undefined | ### TokensUnwrapped @@ -1156,3 +1156,88 @@ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId +## Errors + +### ContractMetadata__NotAuthorized + +```solidity +error ContractMetadata__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set the contract metadata URI.* + + +### Ownable__NotAuthorized + +```solidity +error Ownable__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set the owner.* + + +### Permissions__CanOnlyGrantToNonHolders + +```solidity +error Permissions__CanOnlyGrantToNonHolders(address account) +``` + +Emitted when specified account already has the role. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| account | address | undefined | + +### Permissions__CanOnlyRenounceForSelf + +```solidity +error Permissions__CanOnlyRenounceForSelf(address caller, address account) +``` + +Emitted when calling address is different from the specified account. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| caller | address | undefined | +| account | address | undefined | + +### Royalty__ExceedsMaxBps + +```solidity +error Royalty__ExceedsMaxBps(uint256 royaltyBps) +``` + +Emitted when the given bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| royaltyBps | uint256 | undefined | + +### Royalty__NotAuthorized + +```solidity +error Royalty__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set royalty details.* + + + diff --git a/docs/Ownable.md b/docs/Ownable.md index 82988ff33..2a6559cf2 100644 --- a/docs/Ownable.md +++ b/docs/Ownable.md @@ -4,7 +4,7 @@ - +Thirdweb's `Ownable` is a contract extension to be used with any base contract. It exposes functions for setting and reading who the 'owner' of the inheriting smart contract is, and lets the inheriting contract perform conditional logic that uses information about who the contract's owner is. @@ -50,7 +50,7 @@ function setOwner(address _newOwner) external nonpayable ### OwnerUpdated ```solidity -event OwnerUpdated(address prevOwner, address newOwner) +event OwnerUpdated(address indexed prevOwner, address indexed newOwner) ``` @@ -61,8 +61,22 @@ event OwnerUpdated(address prevOwner, address newOwner) | Name | Type | Description | |---|---|---| -| prevOwner | address | undefined | -| newOwner | address | undefined | +| prevOwner `indexed` | address | undefined | +| newOwner `indexed` | address | undefined | + + + +## Errors + +### Ownable__NotAuthorized + +```solidity +error Ownable__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set the owner.* diff --git a/docs/Pack.md b/docs/Pack.md index c682d8297..38846b1c7 100644 --- a/docs/Pack.md +++ b/docs/Pack.md @@ -375,7 +375,7 @@ function grantRole(bytes32 role, address account) external nonpayable - +*Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.* #### Parameters @@ -415,7 +415,7 @@ function hasRoleWithSwitch(bytes32 role, address account) external view returns - +*Returns `true` if either (1) `account` has been granted `role`, or (2) the relevant role restrictions do not apply at the time of calling this function.* #### Parameters @@ -695,7 +695,7 @@ function renounceRole(bytes32 role, address account) external nonpayable - +*Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`.* #### Parameters @@ -712,7 +712,7 @@ function revokeRole(bytes32 role, address account) external nonpayable - +*Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.* #### Parameters @@ -994,7 +994,7 @@ event ContractURIUpdated(string prevURI, string newURI) ### DefaultRoyalty ```solidity -event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps) +event DefaultRoyalty(address indexed newRoyaltyRecipient, uint256 newRoyaltyBps) ``` @@ -1005,13 +1005,13 @@ event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps) | Name | Type | Description | |---|---|---| -| newRoyaltyRecipient | address | undefined | +| newRoyaltyRecipient `indexed` | address | undefined | | newRoyaltyBps | uint256 | undefined | ### OwnerUpdated ```solidity -event OwnerUpdated(address prevOwner, address newOwner) +event OwnerUpdated(address indexed prevOwner, address indexed newOwner) ``` @@ -1022,8 +1022,8 @@ event OwnerUpdated(address prevOwner, address newOwner) | Name | Type | Description | |---|---|---| -| prevOwner | address | undefined | -| newOwner | address | undefined | +| prevOwner `indexed` | address | undefined | +| newOwner `indexed` | address | undefined | ### PackCreated @@ -1136,7 +1136,7 @@ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed ### RoyaltyForToken ```solidity -event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 royaltyBps) +event RoyaltyForToken(uint256 indexed tokenId, address indexed royaltyRecipient, uint256 royaltyBps) ``` @@ -1148,7 +1148,7 @@ event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 | Name | Type | Description | |---|---|---| | tokenId `indexed` | uint256 | undefined | -| royaltyRecipient | address | undefined | +| royaltyRecipient `indexed` | address | undefined | | royaltyBps | uint256 | undefined | ### TransferBatch @@ -1226,3 +1226,88 @@ event Unpaused(address account) +## Errors + +### ContractMetadata__NotAuthorized + +```solidity +error ContractMetadata__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set the contract metadata URI.* + + +### Ownable__NotAuthorized + +```solidity +error Ownable__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set the owner.* + + +### Permissions__CanOnlyGrantToNonHolders + +```solidity +error Permissions__CanOnlyGrantToNonHolders(address account) +``` + +Emitted when specified account already has the role. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| account | address | undefined | + +### Permissions__CanOnlyRenounceForSelf + +```solidity +error Permissions__CanOnlyRenounceForSelf(address caller, address account) +``` + +Emitted when calling address is different from the specified account. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| caller | address | undefined | +| account | address | undefined | + +### Royalty__ExceedsMaxBps + +```solidity +error Royalty__ExceedsMaxBps(uint256 royaltyBps) +``` + +Emitted when the given bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| royaltyBps | uint256 | undefined | + +### Royalty__NotAuthorized + +```solidity +error Royalty__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set royalty details.* + + + diff --git a/docs/Permissions.md b/docs/Permissions.md index 56b39fc63..09b3600cf 100644 --- a/docs/Permissions.md +++ b/docs/Permissions.md @@ -97,7 +97,7 @@ function hasRoleWithSwitch(bytes32 role, address account) external view returns - +*Returns `true` if either (1) `account` has been granted `role`, or (2) the relevant role restrictions do not apply at the time of calling this function.* #### Parameters @@ -206,3 +206,39 @@ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed +## Errors + +### Permissions__CanOnlyGrantToNonHolders + +```solidity +error Permissions__CanOnlyGrantToNonHolders(address account) +``` + +Emitted when specified account already has the role. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| account | address | undefined | + +### Permissions__CanOnlyRenounceForSelf + +```solidity +error Permissions__CanOnlyRenounceForSelf(address caller, address account) +``` + +Emitted when calling address is different from the specified account. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| caller | address | undefined | +| account | address | undefined | + + diff --git a/docs/PermissionsEnumerable.md b/docs/PermissionsEnumerable.md index 0f46e6af5..c093ca26c 100644 --- a/docs/PermissionsEnumerable.md +++ b/docs/PermissionsEnumerable.md @@ -102,7 +102,7 @@ function grantRole(bytes32 role, address account) external nonpayable - +*Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.* #### Parameters @@ -142,7 +142,7 @@ function hasRoleWithSwitch(bytes32 role, address account) external view returns - +*Returns `true` if either (1) `account` has been granted `role`, or (2) the relevant role restrictions do not apply at the time of calling this function.* #### Parameters @@ -165,7 +165,7 @@ function renounceRole(bytes32 role, address account) external nonpayable - +*Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`.* #### Parameters @@ -182,7 +182,7 @@ function revokeRole(bytes32 role, address account) external nonpayable - +*Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.* #### Parameters @@ -251,3 +251,39 @@ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed +## Errors + +### Permissions__CanOnlyGrantToNonHolders + +```solidity +error Permissions__CanOnlyGrantToNonHolders(address account) +``` + +Emitted when specified account already has the role. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| account | address | undefined | + +### Permissions__CanOnlyRenounceForSelf + +```solidity +error Permissions__CanOnlyRenounceForSelf(address caller, address account) +``` + +Emitted when calling address is different from the specified account. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| caller | address | undefined | +| account | address | undefined | + + diff --git a/docs/PlatformFee.md b/docs/PlatformFee.md index 7c53f7063..148b41b71 100644 --- a/docs/PlatformFee.md +++ b/docs/PlatformFee.md @@ -4,7 +4,7 @@ - +Thirdweb's `PlatformFee` is a contract extension to be used with any base contract. It exposes functions for setting and reading the recipient of platform fee and the platform fee basis points, and lets the inheriting contract perform conditional logic that uses information about platform fees, if desired. @@ -52,7 +52,7 @@ function setPlatformFeeInfo(address _platformFeeRecipient, uint256 _platformFeeB ### PlatformFeeInfoUpdated ```solidity -event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBps) +event PlatformFeeInfoUpdated(address indexed platformFeeRecipient, uint256 platformFeeBps) ``` @@ -63,8 +63,38 @@ event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBp | Name | Type | Description | |---|---|---| -| platformFeeRecipient | address | undefined | +| platformFeeRecipient `indexed` | address | undefined | | platformFeeBps | uint256 | undefined | +## Errors + +### PlatformFee__ExceedsMaxBps + +```solidity +error PlatformFee__ExceedsMaxBps(uint256 platformFeeBps) +``` + +Emitted when given platform-fee bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| platformFeeBps | uint256 | undefined | + +### PlatformFee__NotAuthorized + +```solidity +error PlatformFee__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set platform fee details.* + + + diff --git a/docs/PrimarySale.md b/docs/PrimarySale.md index 00684208c..60a8510a5 100644 --- a/docs/PrimarySale.md +++ b/docs/PrimarySale.md @@ -4,7 +4,7 @@ - +Thirdweb's `Primary` is a contract extension to be used with any base contract. It exposes functions for setting and reading the recipient of primary sales, and lets the inheriting contract perform conditional logic that uses information about primary sales, if desired. @@ -65,3 +65,17 @@ event PrimarySaleRecipientUpdated(address indexed recipient) +## Errors + +### PrimarySale__NotAuthorized + +```solidity +error PrimarySale__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set primary sales details.* + + + diff --git a/docs/Royalty.md b/docs/Royalty.md index e1abd57b5..3504e24c5 100644 --- a/docs/Royalty.md +++ b/docs/Royalty.md @@ -4,7 +4,7 @@ - +Thirdweb's `Royalty` is a contract extension to be used with any base contract. It exposes functions for setting and reading the recipient of royalty fee and the royalty fee basis points, and lets the inheriting contract perform conditional logic that uses information about royalty fees, if desired. The `Royalty` contract is ERC2981 compliant. @@ -117,7 +117,7 @@ function setRoyaltyInfoForToken(uint256 _tokenId, address _recipient, uint256 _b ### DefaultRoyalty ```solidity -event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps) +event DefaultRoyalty(address indexed newRoyaltyRecipient, uint256 newRoyaltyBps) ``` @@ -128,13 +128,13 @@ event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps) | Name | Type | Description | |---|---|---| -| newRoyaltyRecipient | address | undefined | +| newRoyaltyRecipient `indexed` | address | undefined | | newRoyaltyBps | uint256 | undefined | ### RoyaltyForToken ```solidity -event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 royaltyBps) +event RoyaltyForToken(uint256 indexed tokenId, address indexed royaltyRecipient, uint256 royaltyBps) ``` @@ -146,8 +146,38 @@ event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 | Name | Type | Description | |---|---|---| | tokenId `indexed` | uint256 | undefined | -| royaltyRecipient | address | undefined | +| royaltyRecipient `indexed` | address | undefined | | royaltyBps | uint256 | undefined | +## Errors + +### Royalty__ExceedsMaxBps + +```solidity +error Royalty__ExceedsMaxBps(uint256 royaltyBps) +``` + +Emitted when the given bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| royaltyBps | uint256 | undefined | + +### Royalty__NotAuthorized + +```solidity +error Royalty__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set royalty details.* + + + diff --git a/docs/SignatureDrop.md b/docs/SignatureDrop.md index 33c5b1b96..10c47c753 100644 --- a/docs/SignatureDrop.md +++ b/docs/SignatureDrop.md @@ -85,7 +85,7 @@ function burn(uint256 tokenId) external nonpayable ### claim ```solidity -function claim(address _receiver, uint256 _quantity, address _currency, uint256 _pricePerToken, IDrop.AllowlistProof _allowlistProof, bytes _data) external payable +function claim(address _receiver, uint256 _quantity, address _currency, uint256 _pricePerToken, IDropSinglePhase.AllowlistProof _allowlistProof, bytes _data) external payable ``` @@ -100,7 +100,7 @@ function claim(address _receiver, uint256 _quantity, address _currency, uint256 | _quantity | uint256 | undefined | _currency | address | undefined | _pricePerToken | uint256 | undefined -| _allowlistProof | IDrop.AllowlistProof | undefined +| _allowlistProof | IDropSinglePhase.AllowlistProof | undefined | _data | bytes | undefined ### claimCondition @@ -346,7 +346,7 @@ function getPlatformFeeInfo() external view returns (address, uint16) ### getRevealURI ```solidity -function getRevealURI(uint256 _batchId, bytes _key) external nonpayable returns (string revealedURI) +function getRevealURI(uint256 _batchId, bytes _key) external view returns (string revealedURI) ``` @@ -464,7 +464,7 @@ function grantRole(bytes32 role, address account) external nonpayable - +*Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.* #### Parameters @@ -504,7 +504,7 @@ function hasRoleWithSwitch(bytes32 role, address account) external view returns - +*Returns `true` if either (1) `account` has been granted `role`, or (2) the relevant role restrictions do not apply at the time of calling this function.* #### Parameters @@ -778,7 +778,7 @@ function renounceRole(bytes32 role, address account) external nonpayable - +*Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`.* #### Parameters @@ -818,7 +818,7 @@ function revokeRole(bytes32 role, address account) external nonpayable - +*Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.* #### Parameters @@ -1147,7 +1147,7 @@ function verifyClaim(address _claimer, uint256 _quantity, address _currency, uin ### verifyClaimMerkleProof ```solidity -function verifyClaimMerkleProof(address _claimer, uint256 _quantity, IDrop.AllowlistProof _allowlistProof) external view returns (bool validMerkleProof, uint256 merkleProofIndex) +function verifyClaimMerkleProof(address _claimer, uint256 _quantity, IDropSinglePhase.AllowlistProof _allowlistProof) external view returns (bool validMerkleProof, uint256 merkleProofIndex) ``` @@ -1160,7 +1160,7 @@ function verifyClaimMerkleProof(address _claimer, uint256 _quantity, IDrop.Allow |---|---|---| | _claimer | address | undefined | _quantity | uint256 | undefined -| _allowlistProof | IDrop.AllowlistProof | undefined +| _allowlistProof | IDropSinglePhase.AllowlistProof | undefined #### Returns @@ -1212,7 +1212,7 @@ event ApprovalForAll(address indexed owner, address indexed operator, bool appro ### ClaimConditionUpdated ```solidity -event ClaimConditionUpdated(IClaimCondition.ClaimCondition claimConditions, bool resetClaimEligibility) +event ClaimConditionUpdated(IClaimCondition.ClaimCondition condition, bool resetEligibility) ``` @@ -1223,8 +1223,8 @@ event ClaimConditionUpdated(IClaimCondition.ClaimCondition claimConditions, bool | Name | Type | Description | |---|---|---| -| claimConditions | IClaimCondition.ClaimCondition | undefined | -| resetClaimEligibility | bool | undefined | +| condition | IClaimCondition.ClaimCondition | undefined | +| resetEligibility | bool | undefined | ### ContractURIUpdated @@ -1246,7 +1246,7 @@ event ContractURIUpdated(string prevURI, string newURI) ### DefaultRoyalty ```solidity -event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps) +event DefaultRoyalty(address indexed newRoyaltyRecipient, uint256 newRoyaltyBps) ``` @@ -1257,13 +1257,13 @@ event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps) | Name | Type | Description | |---|---|---| -| newRoyaltyRecipient | address | undefined | +| newRoyaltyRecipient `indexed` | address | undefined | | newRoyaltyBps | uint256 | undefined | ### OwnerUpdated ```solidity -event OwnerUpdated(address prevOwner, address newOwner) +event OwnerUpdated(address indexed prevOwner, address indexed newOwner) ``` @@ -1274,13 +1274,13 @@ event OwnerUpdated(address prevOwner, address newOwner) | Name | Type | Description | |---|---|---| -| prevOwner | address | undefined | -| newOwner | address | undefined | +| prevOwner `indexed` | address | undefined | +| newOwner `indexed` | address | undefined | ### PlatformFeeInfoUpdated ```solidity -event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBps) +event PlatformFeeInfoUpdated(address indexed platformFeeRecipient, uint256 platformFeeBps) ``` @@ -1291,7 +1291,7 @@ event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBp | Name | Type | Description | |---|---|---| -| platformFeeRecipient | address | undefined | +| platformFeeRecipient `indexed` | address | undefined | | platformFeeBps | uint256 | undefined | ### PrimarySaleRecipientUpdated @@ -1367,7 +1367,7 @@ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed ### RoyaltyForToken ```solidity -event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 royaltyBps) +event RoyaltyForToken(uint256 indexed tokenId, address indexed royaltyRecipient, uint256 royaltyBps) ``` @@ -1379,13 +1379,13 @@ event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 | Name | Type | Description | |---|---|---| | tokenId `indexed` | uint256 | undefined | -| royaltyRecipient | address | undefined | +| royaltyRecipient `indexed` | address | undefined | | royaltyBps | uint256 | undefined | ### TokenURIRevealed ```solidity -event TokenURIRevealed(uint256 index, string revealedURI) +event TokenURIRevealed(uint256 indexed index, string revealedURI) ``` @@ -1396,13 +1396,13 @@ event TokenURIRevealed(uint256 index, string revealedURI) | Name | Type | Description | |---|---|---| -| index | uint256 | undefined | +| index `indexed` | uint256 | undefined | | revealedURI | string | undefined | ### TokensClaimed ```solidity -event TokensClaimed(uint256 indexed claimConditionIndex, address indexed claimer, address indexed receiver, uint256 startTokenId, uint256 quantityClaimed) +event TokensClaimed(address indexed claimer, address indexed receiver, uint256 indexed startTokenId, uint256 quantityClaimed) ``` @@ -1413,16 +1413,15 @@ event TokensClaimed(uint256 indexed claimConditionIndex, address indexed claimer | Name | Type | Description | |---|---|---| -| claimConditionIndex `indexed` | uint256 | undefined | | claimer `indexed` | address | undefined | | receiver `indexed` | address | undefined | -| startTokenId | uint256 | undefined | +| startTokenId `indexed` | uint256 | undefined | | quantityClaimed | uint256 | undefined | ### TokensLazyMinted ```solidity -event TokensLazyMinted(uint256 startTokenId, uint256 endTokenId, string baseURI, bytes encryptedBaseURI) +event TokensLazyMinted(uint256 indexed startTokenId, uint256 endTokenId, string baseURI, bytes encryptedBaseURI) ``` @@ -1433,7 +1432,7 @@ event TokensLazyMinted(uint256 startTokenId, uint256 endTokenId, string baseURI, | Name | Type | Description | |---|---|---| -| startTokenId | uint256 | undefined | +| startTokenId `indexed` | uint256 | undefined | | endTokenId | uint256 | undefined | | baseURI | string | undefined | | encryptedBaseURI | bytes | undefined | @@ -1534,6 +1533,212 @@ Cannot query the balance for the zero address. +### ContractMetadata__NotAuthorized + +```solidity +error ContractMetadata__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set the contract metadata URI.* + + +### DelayedReveal__NothingToReveal + +```solidity +error DelayedReveal__NothingToReveal(uint256 batchId) +``` + +Emitted when encrypted URI for a given batch is empty. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| batchId | uint256 | undefined | + +### DropSinglePhase__CannotClaimYet + +```solidity +error DropSinglePhase__CannotClaimYet(uint256 blockTimestamp, uint256 startTimestamp, uint256 lastClaimedAt, uint256 nextValidClaimTimestamp) +``` + +Emitted when the current timestamp is invalid for claim. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| blockTimestamp | uint256 | undefined | +| startTimestamp | uint256 | undefined | +| lastClaimedAt | uint256 | undefined | +| nextValidClaimTimestamp | uint256 | undefined | + +### DropSinglePhase__ExceedMaxClaimableSupply + +```solidity +error DropSinglePhase__ExceedMaxClaimableSupply(uint256 supplyClaimed, uint256 maxClaimableSupply) +``` + +Emitted when claiming given quantity will exceed max claimable supply. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| supplyClaimed | uint256 | undefined | +| maxClaimableSupply | uint256 | undefined | + +### DropSinglePhase__InvalidCurrencyOrPrice + +```solidity +error DropSinglePhase__InvalidCurrencyOrPrice(address givenCurrency, address requiredCurrency, uint256 givenPricePerToken, uint256 requiredPricePerToken) +``` + +Emitted when given currency or price is invalid. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| givenCurrency | address | undefined | +| requiredCurrency | address | undefined | +| givenPricePerToken | uint256 | undefined | +| requiredPricePerToken | uint256 | undefined | + +### DropSinglePhase__InvalidQuantity + +```solidity +error DropSinglePhase__InvalidQuantity() +``` + +Emitted when claiming invalid quantity of tokens. + + + + +### DropSinglePhase__InvalidQuantityProof + +```solidity +error DropSinglePhase__InvalidQuantityProof(uint256 maxQuantityInAllowlist) +``` + +Emitted when claiming more than allowed quantity in allowlist. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| maxQuantityInAllowlist | uint256 | undefined | + +### DropSinglePhase__MaxSupplyClaimedAlready + +```solidity +error DropSinglePhase__MaxSupplyClaimedAlready(uint256 supplyClaimedAlready) +``` + +Emitted when max claimable supply in given condition is less than supply claimed already. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| supplyClaimedAlready | uint256 | undefined | + +### DropSinglePhase__NotAuthorized + +```solidity +error DropSinglePhase__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set claim conditions.* + + +### DropSinglePhase__NotInWhitelist + +```solidity +error DropSinglePhase__NotInWhitelist() +``` + +Emitted when given allowlist proof is invalid. + + + + +### DropSinglePhase__ProofClaimed + +```solidity +error DropSinglePhase__ProofClaimed() +``` + +Emitted when allowlist spot is already used. + + + + +### LazyMint__InvalidIndex + +```solidity +error LazyMint__InvalidIndex(uint256 index) +``` + +Emitted when the given index is equal to or higher than total number of batches. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| index | uint256 | undefined | + +### LazyMint__NoBaseURIForToken + +```solidity +error LazyMint__NoBaseURIForToken(uint256 tokenId) +``` + +Emitted when there's no Base URI set for the given token ID. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| tokenId | uint256 | undefined | + +### LazyMint__NoBatchIDForToken + +```solidity +error LazyMint__NoBatchIDForToken(uint256 tokenId) +``` + +Emitted when the given token ID doesn't belong to any batch. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| tokenId | uint256 | undefined | + ### MintToZeroAddress ```solidity @@ -1556,6 +1761,17 @@ The quantity of tokens minted must be more than zero. +### Ownable__NotAuthorized + +```solidity +error Ownable__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set the owner.* + + ### OwnerQueryForNonexistentToken ```solidity @@ -1567,6 +1783,198 @@ The token does not exist. +### Permissions__CanOnlyGrantToNonHolders + +```solidity +error Permissions__CanOnlyGrantToNonHolders(address account) +``` + +Emitted when specified account already has the role. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| account | address | undefined | + +### Permissions__CanOnlyRenounceForSelf + +```solidity +error Permissions__CanOnlyRenounceForSelf(address caller, address account) +``` + +Emitted when calling address is different from the specified account. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| caller | address | undefined | +| account | address | undefined | + +### PlatformFee__ExceedsMaxBps + +```solidity +error PlatformFee__ExceedsMaxBps(uint256 platformFeeBps) +``` + +Emitted when given platform-fee bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| platformFeeBps | uint256 | undefined | + +### PlatformFee__NotAuthorized + +```solidity +error PlatformFee__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set platform fee details.* + + +### PrimarySale__NotAuthorized + +```solidity +error PrimarySale__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set primary sales details.* + + +### Royalty__ExceedsMaxBps + +```solidity +error Royalty__ExceedsMaxBps(uint256 royaltyBps) +``` + +Emitted when the given bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| royaltyBps | uint256 | undefined | + +### Royalty__NotAuthorized + +```solidity +error Royalty__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set royalty details.* + + +### SignatureDrop__MintingZeroTokens + +```solidity +error SignatureDrop__MintingZeroTokens() +``` + +Emitted when given quantity to mint is zero. + + + + +### SignatureDrop__MustSendTotalPrice + +```solidity +error SignatureDrop__MustSendTotalPrice(uint256 sentValue, uint256 totalPrice) +``` + +Emitted when sent value doesn't match the total price of tokens. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| sentValue | uint256 | undefined | +| totalPrice | uint256 | undefined | + +### SignatureDrop__NotEnoughMintedTokens + +```solidity +error SignatureDrop__NotEnoughMintedTokens(uint256 currentIndex, uint256 quantity) +``` + +Emitted when minting the given quantity will exceed available quantity. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| currentIndex | uint256 | undefined | +| quantity | uint256 | undefined | + +### SignatureDrop__NotTransferRole + +```solidity +error SignatureDrop__NotTransferRole() +``` + +Emitted when given address doesn't have transfer role. + + + + +### SignatureDrop__ZeroAmount + +```solidity +error SignatureDrop__ZeroAmount() +``` + +Emitted when given amount for lazy-minting is zero. + + + + +### SignatureMintERC721__InvalidRequest + +```solidity +error SignatureMintERC721__InvalidRequest() +``` + +Emitted when either the signature or the request uid is invalid. + + + + +### SignatureMintERC721__RequestExpired + +```solidity +error SignatureMintERC721__RequestExpired(uint256 blockTimestamp) +``` + +Emitted when block-timestamp is outside of validity start and end range. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| blockTimestamp | uint256 | undefined | + ### TransferCallerNotOwnerNorApproved ```solidity diff --git a/docs/SignatureMintERC721.md b/docs/SignatureMintERC721.md index cdaf51432..690d33e19 100644 --- a/docs/SignatureMintERC721.md +++ b/docs/SignatureMintERC721.md @@ -82,3 +82,33 @@ event TokensMintedWithSignature(address indexed signer, address indexed mintedTo +## Errors + +### SignatureMintERC721__InvalidRequest + +```solidity +error SignatureMintERC721__InvalidRequest() +``` + +Emitted when either the signature or the request uid is invalid. + + + + +### SignatureMintERC721__RequestExpired + +```solidity +error SignatureMintERC721__RequestExpired(uint256 blockTimestamp) +``` + +Emitted when block-timestamp is outside of validity start and end range. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| blockTimestamp | uint256 | undefined | + + diff --git a/docs/SignatureMintERC721Upgradeable.md b/docs/SignatureMintERC721Upgradeable.md index 8c7dc170d..0fcced875 100644 --- a/docs/SignatureMintERC721Upgradeable.md +++ b/docs/SignatureMintERC721Upgradeable.md @@ -82,3 +82,33 @@ event TokensMintedWithSignature(address indexed signer, address indexed mintedTo +## Errors + +### SignatureMintERC721__InvalidRequest + +```solidity +error SignatureMintERC721__InvalidRequest() +``` + +Emitted when either the signature or the request uid is invalid. + + + + +### SignatureMintERC721__RequestExpired + +```solidity +error SignatureMintERC721__RequestExpired(uint256 blockTimestamp) +``` + +Emitted when block-timestamp is outside of validity start and end range. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| blockTimestamp | uint256 | undefined | + + diff --git a/docs/ThirdwebContract.md b/docs/ThirdwebContract.md index b67d6792b..386f220f8 100644 --- a/docs/ThirdwebContract.md +++ b/docs/ThirdwebContract.md @@ -66,7 +66,7 @@ function tw_initializeOwner(address deployer) external nonpayable ### OwnerUpdated ```solidity -event OwnerUpdated(address prevOwner, address newOwner) +event OwnerUpdated(address indexed prevOwner, address indexed newOwner) ``` @@ -77,8 +77,22 @@ event OwnerUpdated(address prevOwner, address newOwner) | Name | Type | Description | |---|---|---| -| prevOwner | address | undefined | -| newOwner | address | undefined | +| prevOwner `indexed` | address | undefined | +| newOwner `indexed` | address | undefined | + + + +## Errors + +### Ownable__NotAuthorized + +```solidity +error Ownable__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set the owner.* diff --git a/docs/TokenERC1155.md b/docs/TokenERC1155.md index 288dc3350..e837d9fdb 100644 --- a/docs/TokenERC1155.md +++ b/docs/TokenERC1155.md @@ -942,7 +942,7 @@ event ApprovalForAll(address indexed account, address indexed operator, bool app ### DefaultRoyalty ```solidity -event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps) +event DefaultRoyalty(address indexed newRoyaltyRecipient, uint256 newRoyaltyBps) ``` @@ -953,13 +953,13 @@ event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps) | Name | Type | Description | |---|---|---| -| newRoyaltyRecipient | address | undefined | +| newRoyaltyRecipient `indexed` | address | undefined | | newRoyaltyBps | uint256 | undefined | ### OwnerUpdated ```solidity -event OwnerUpdated(address prevOwner, address newOwner) +event OwnerUpdated(address indexed prevOwner, address indexed newOwner) ``` @@ -970,13 +970,13 @@ event OwnerUpdated(address prevOwner, address newOwner) | Name | Type | Description | |---|---|---| -| prevOwner | address | undefined | -| newOwner | address | undefined | +| prevOwner `indexed` | address | undefined | +| newOwner `indexed` | address | undefined | ### PlatformFeeInfoUpdated ```solidity -event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBps) +event PlatformFeeInfoUpdated(address indexed platformFeeRecipient, uint256 platformFeeBps) ``` @@ -987,7 +987,7 @@ event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBp | Name | Type | Description | |---|---|---| -| platformFeeRecipient | address | undefined | +| platformFeeRecipient `indexed` | address | undefined | | platformFeeBps | uint256 | undefined | ### PrimarySaleRecipientUpdated @@ -1063,7 +1063,7 @@ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed ### RoyaltyForToken ```solidity -event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 royaltyBps) +event RoyaltyForToken(uint256 indexed tokenId, address indexed royaltyRecipient, uint256 royaltyBps) ``` @@ -1075,7 +1075,7 @@ event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 | Name | Type | Description | |---|---|---| | tokenId `indexed` | uint256 | undefined | -| royaltyRecipient | address | undefined | +| royaltyRecipient `indexed` | address | undefined | | royaltyBps | uint256 | undefined | ### TokensMinted @@ -1175,3 +1175,82 @@ event URI(string value, uint256 indexed id) +## Errors + +### Ownable__NotAuthorized + +```solidity +error Ownable__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set the owner.* + + +### PlatformFee__ExceedsMaxBps + +```solidity +error PlatformFee__ExceedsMaxBps(uint256 platformFeeBps) +``` + +Emitted when given platform-fee bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| platformFeeBps | uint256 | undefined | + +### PlatformFee__NotAuthorized + +```solidity +error PlatformFee__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set platform fee details.* + + +### PrimarySale__NotAuthorized + +```solidity +error PrimarySale__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set primary sales details.* + + +### Royalty__ExceedsMaxBps + +```solidity +error Royalty__ExceedsMaxBps(uint256 royaltyBps) +``` + +Emitted when the given bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| royaltyBps | uint256 | undefined | + +### Royalty__NotAuthorized + +```solidity +error Royalty__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set royalty details.* + + + diff --git a/docs/TokenERC20.md b/docs/TokenERC20.md index 6831346e6..da2924247 100644 --- a/docs/TokenERC20.md +++ b/docs/TokenERC20.md @@ -1060,7 +1060,7 @@ event Paused(address account) ### PlatformFeeInfoUpdated ```solidity -event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBps) +event PlatformFeeInfoUpdated(address indexed platformFeeRecipient, uint256 platformFeeBps) ``` @@ -1071,7 +1071,7 @@ event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBp | Name | Type | Description | |---|---|---| -| platformFeeRecipient | address | undefined | +| platformFeeRecipient `indexed` | address | undefined | | platformFeeBps | uint256 | undefined | ### PrimarySaleRecipientUpdated @@ -1215,3 +1215,44 @@ event Unpaused(address account) +## Errors + +### PlatformFee__ExceedsMaxBps + +```solidity +error PlatformFee__ExceedsMaxBps(uint256 platformFeeBps) +``` + +Emitted when given platform-fee bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| platformFeeBps | uint256 | undefined | + +### PlatformFee__NotAuthorized + +```solidity +error PlatformFee__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set platform fee details.* + + +### PrimarySale__NotAuthorized + +```solidity +error PrimarySale__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set primary sales details.* + + + diff --git a/docs/TokenERC721.md b/docs/TokenERC721.md index 5b29e087b..ed06a8398 100644 --- a/docs/TokenERC721.md +++ b/docs/TokenERC721.md @@ -1002,7 +1002,7 @@ event ApprovalForAll(address indexed owner, address indexed operator, bool appro ### DefaultRoyalty ```solidity -event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps) +event DefaultRoyalty(address indexed newRoyaltyRecipient, uint256 newRoyaltyBps) ``` @@ -1013,13 +1013,13 @@ event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps) | Name | Type | Description | |---|---|---| -| newRoyaltyRecipient | address | undefined | +| newRoyaltyRecipient `indexed` | address | undefined | | newRoyaltyBps | uint256 | undefined | ### OwnerUpdated ```solidity -event OwnerUpdated(address prevOwner, address newOwner) +event OwnerUpdated(address indexed prevOwner, address indexed newOwner) ``` @@ -1030,13 +1030,13 @@ event OwnerUpdated(address prevOwner, address newOwner) | Name | Type | Description | |---|---|---| -| prevOwner | address | undefined | -| newOwner | address | undefined | +| prevOwner `indexed` | address | undefined | +| newOwner `indexed` | address | undefined | ### PlatformFeeInfoUpdated ```solidity -event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBps) +event PlatformFeeInfoUpdated(address indexed platformFeeRecipient, uint256 platformFeeBps) ``` @@ -1047,7 +1047,7 @@ event PlatformFeeInfoUpdated(address platformFeeRecipient, uint256 platformFeeBp | Name | Type | Description | |---|---|---| -| platformFeeRecipient | address | undefined | +| platformFeeRecipient `indexed` | address | undefined | | platformFeeBps | uint256 | undefined | ### PrimarySaleRecipientUpdated @@ -1123,7 +1123,7 @@ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed ### RoyaltyForToken ```solidity -event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 royaltyBps) +event RoyaltyForToken(uint256 indexed tokenId, address indexed royaltyRecipient, uint256 royaltyBps) ``` @@ -1135,7 +1135,7 @@ event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 | Name | Type | Description | |---|---|---| | tokenId `indexed` | uint256 | undefined | -| royaltyRecipient | address | undefined | +| royaltyRecipient `indexed` | address | undefined | | royaltyBps | uint256 | undefined | ### TokensMinted @@ -1195,3 +1195,82 @@ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId +## Errors + +### Ownable__NotAuthorized + +```solidity +error Ownable__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set the owner.* + + +### PlatformFee__ExceedsMaxBps + +```solidity +error PlatformFee__ExceedsMaxBps(uint256 platformFeeBps) +``` + +Emitted when given platform-fee bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| platformFeeBps | uint256 | undefined | + +### PlatformFee__NotAuthorized + +```solidity +error PlatformFee__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set platform fee details.* + + +### PrimarySale__NotAuthorized + +```solidity +error PrimarySale__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set primary sales details.* + + +### Royalty__ExceedsMaxBps + +```solidity +error Royalty__ExceedsMaxBps(uint256 royaltyBps) +``` + +Emitted when the given bps exceeds max bps. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| royaltyBps | uint256 | undefined | + +### Royalty__NotAuthorized + +```solidity +error Royalty__NotAuthorized() +``` + + + +*Emitted when an unauthorized caller tries to set royalty details.* + + + diff --git a/src/test/ContractPublisher.t.sol b/src/test/ContractPublisher.t.sol index 73f43e6cc..2bb7b4048 100644 --- a/src/test/ContractPublisher.t.sol +++ b/src/test/ContractPublisher.t.sol @@ -85,31 +85,32 @@ contract ContractPublisherTest is BaseTest, IContractPublisherData { assertEq(customContract.implementation, address(0)); } - function test_publish_viaOperator() public { - string memory contractId = "MyContract"; - - vm.prank(publisher); - byoc.approveOperator(operator, true); - - vm.prank(operator); - byoc.publishContract( - publisher, - publishMetadataUri, - keccak256(type(MockCustomContract).creationCode), - address(0), - contractId - ); - - IContractPublisher.CustomContractInstance memory customContract = byoc.getPublishedContract( - publisher, - contractId - ); - - assertEq(customContract.contractId, contractId); - assertEq(customContract.publishMetadataUri, publishMetadataUri); - assertEq(customContract.bytecodeHash, keccak256(type(MockCustomContract).creationCode)); - assertEq(customContract.implementation, address(0)); - } + // Deprecated + // function test_publish_viaOperator() public { + // string memory contractId = "MyContract"; + + // vm.prank(publisher); + // byoc.approveOperator(operator, true); + + // vm.prank(operator); + // byoc.publishContract( + // publisher, + // publishMetadataUri, + // keccak256(type(MockCustomContract).creationCode), + // address(0), + // contractId + // ); + + // IContractPublisher.CustomContractInstance memory customContract = byoc.getPublishedContract( + // publisher, + // contractId + // ); + + // assertEq(customContract.contractId, contractId); + // assertEq(customContract.publishMetadataUri, publishMetadataUri); + // assertEq(customContract.bytecodeHash, keccak256(type(MockCustomContract).creationCode)); + // assertEq(customContract.implementation, address(0)); + // } function test_publish_revert_unapprovedCaller() public { string memory contractId = "MyContract"; @@ -144,34 +145,35 @@ contract ContractPublisherTest is BaseTest, IContractPublisherData { ); } - function test_publish_emit_ContractPublished() public { - string memory contractId = "MyContract"; - - vm.prank(publisher); - byoc.approveOperator(operator, true); - - IContractPublisher.CustomContractInstance memory expectedCustomContract = IContractPublisher - .CustomContractInstance({ - contractId: contractId, - publishTimestamp: 100, - publishMetadataUri: publishMetadataUri, - bytecodeHash: keccak256(type(MockCustomContract).creationCode), - implementation: address(0) - }); - - vm.expectEmit(true, true, true, true); - emit ContractPublished(operator, publisher, expectedCustomContract); - - vm.warp(100); - vm.prank(operator); - byoc.publishContract( - publisher, - publishMetadataUri, - keccak256(type(MockCustomContract).creationCode), - address(0), - contractId - ); - } + // Deprecated + // function test_publish_emit_ContractPublished() public { + // string memory contractId = "MyContract"; + + // vm.prank(publisher); + // byoc.approveOperator(operator, true); + + // IContractPublisher.CustomContractInstance memory expectedCustomContract = IContractPublisher + // .CustomContractInstance({ + // contractId: contractId, + // publishTimestamp: 100, + // publishMetadataUri: publishMetadataUri, + // bytecodeHash: keccak256(type(MockCustomContract).creationCode), + // implementation: address(0) + // }); + + // vm.expectEmit(true, true, true, true); + // emit ContractPublished(operator, publisher, expectedCustomContract); + + // vm.warp(100); + // vm.prank(operator); + // byoc.publishContract( + // publisher, + // publishMetadataUri, + // keccak256(type(MockCustomContract).creationCode), + // address(0), + // contractId + // ); + // } function test_unpublish() public { string memory contractId = "MyContract"; @@ -199,34 +201,35 @@ contract ContractPublisherTest is BaseTest, IContractPublisherData { assertEq(customContract.implementation, address(0)); } - function test_unpublish_viaOperator() public { - string memory contractId = "MyContract"; + // Deprecated + // function test_unpublish_viaOperator() public { + // string memory contractId = "MyContract"; - vm.prank(publisher); - byoc.publishContract( - publisher, - publishMetadataUri, - keccak256(type(MockCustomContract).creationCode), - address(0), - contractId - ); + // vm.prank(publisher); + // byoc.publishContract( + // publisher, + // publishMetadataUri, + // keccak256(type(MockCustomContract).creationCode), + // address(0), + // contractId + // ); - vm.prank(publisher); - byoc.approveOperator(operator, true); + // vm.prank(publisher); + // byoc.approveOperator(operator, true); - vm.prank(operator); - byoc.unpublishContract(publisher, contractId); + // vm.prank(operator); + // byoc.unpublishContract(publisher, contractId); - IContractPublisher.CustomContractInstance memory customContract = byoc.getPublishedContract( - publisher, - contractId - ); + // IContractPublisher.CustomContractInstance memory customContract = byoc.getPublishedContract( + // publisher, + // contractId + // ); - assertEq(customContract.contractId, ""); - assertEq(customContract.publishMetadataUri, ""); - assertEq(customContract.bytecodeHash, bytes32(0)); - assertEq(customContract.implementation, address(0)); - } + // assertEq(customContract.contractId, ""); + // assertEq(customContract.publishMetadataUri, ""); + // assertEq(customContract.bytecodeHash, bytes32(0)); + // assertEq(customContract.implementation, address(0)); + // } function test_unpublish_revert_unapprovedCaller() public { string memory contractId = "MyContract"; @@ -267,25 +270,26 @@ contract ContractPublisherTest is BaseTest, IContractPublisherData { byoc.unpublishContract(publisher, contractId); } - function test_unpublish_emit_ContractUnpublished() public { - string memory contractId = "MyContract"; + // Deprecated + // function test_unpublish_emit_ContractUnpublished() public { + // string memory contractId = "MyContract"; - vm.prank(publisher); - byoc.publishContract( - publisher, - publishMetadataUri, - keccak256(type(MockCustomContract).creationCode), - address(0), - contractId - ); + // vm.prank(publisher); + // byoc.publishContract( + // publisher, + // publishMetadataUri, + // keccak256(type(MockCustomContract).creationCode), + // address(0), + // contractId + // ); - vm.prank(publisher); - byoc.approveOperator(operator, true); + // vm.prank(publisher); + // byoc.approveOperator(operator, true); - vm.expectEmit(true, true, true, true); - emit ContractUnpublished(operator, publisher, contractId); + // vm.expectEmit(true, true, true, true); + // emit ContractUnpublished(operator, publisher, contractId); - vm.prank(operator); - byoc.unpublishContract(publisher, contractId); - } + // vm.prank(operator); + // byoc.unpublishContract(publisher, contractId); + // } } diff --git a/src/test/Multiwrap.t.sol b/src/test/Multiwrap.t.sol index d3e84a90b..f29c50d6b 100644 --- a/src/test/Multiwrap.t.sol +++ b/src/test/Multiwrap.t.sol @@ -5,6 +5,7 @@ import { Multiwrap } from "contracts/multiwrap/Multiwrap.sol"; import { ITokenBundle } from "contracts/feature/interface/ITokenBundle.sol"; // Test imports +import "contracts/lib/TWStrings.sol"; import { MockERC20 } from "./mocks/MockERC20.sol"; import { Wallet } from "./utils/Wallet.sol"; import "./utils/BaseTest.sol"; @@ -13,7 +14,7 @@ contract MultiwrapReentrant is MockERC20, ITokenBundle { Multiwrap internal multiwrap; uint256 internal tokenIdOfWrapped = 0; - constructor(address _multiwrap) { + constructor(address payable _multiwrap) { multiwrap = Multiwrap(_multiwrap); } @@ -57,7 +58,7 @@ contract MultiwrapTest is BaseTest { super.setUp(); // Get target contract - multiwrap = Multiwrap(getContract("Multiwrap")); + multiwrap = Multiwrap(payable(getContract("Multiwrap"))); // Set test vars tokenOwner = getWallet(); @@ -103,6 +104,50 @@ contract MultiwrapTest is BaseTest { multiwrap.grantRole(keccak256("MINTER_ROLE"), address(tokenOwner)); } + /*/////////////////////////////////////////////////////////////// + Unit tests: misc. + //////////////////////////////////////////////////////////////*/ + + /** + * note: Tests whether contract revert when a non-holder renounces a role. + */ + function test_revert_nonHolder_renounceRole() public { + address caller = address(0x123); + bytes32 role = keccak256("MINTER_ROLE"); + + vm.prank(caller); + vm.expectRevert( + abi.encodePacked( + "Permissions: account ", + TWStrings.toHexString(uint160(caller), 20), + " is missing role ", + TWStrings.toHexString(uint256(role), 32) + ) + ); + + multiwrap.renounceRole(role, caller); + } + + /** + * note: Tests whether contract revert when a role admin revokes a role for a non-holder. + */ + function test_revert_revokeRoleForNonHolder() public { + address target = address(0x123); + bytes32 role = keccak256("MINTER_ROLE"); + + vm.prank(deployer); + vm.expectRevert( + abi.encodePacked( + "Permissions: account ", + TWStrings.toHexString(uint160(target), 20), + " is missing role ", + TWStrings.toHexString(uint256(role), 32) + ) + ); + + multiwrap.revokeRole(role, target); + } + /** * Unit tests for relevant functions: * - `wrap` @@ -263,7 +308,7 @@ contract MultiwrapTest is BaseTest { * note: Testing revert condition; token owner calls `wrap` to wrap owned tokens. */ function test_revert_wrap_reentrancy() public { - MultiwrapReentrant reentrant = new MultiwrapReentrant(address(multiwrap)); + MultiwrapReentrant reentrant = new MultiwrapReentrant(payable(address(multiwrap))); ITokenBundle.Token[] memory reentrantContentToWrap = new ITokenBundle.Token[](1); reentrant.mint(address(tokenOwner), 10 ether); @@ -354,7 +399,7 @@ contract MultiwrapTest is BaseTest { /** * note: Testing revert condition; token owner calls `wrap` to wrap native tokens, but with multiple instances in `tokensToWrap` array. */ - function test_revert_wrap_nativeTokens_insufficientValue_multipleInstances() public { + function test_balances_wrap_nativeTokens_multipleInstances() public { address recipient = address(0x123); ITokenBundle.Token[] memory nativeTokenContentToWrap = new ITokenBundle.Token[](2); @@ -374,8 +419,9 @@ contract MultiwrapTest is BaseTest { }); vm.prank(address(tokenOwner)); - vm.expectRevert("msg.value != amount"); multiwrap.wrap{ value: 10 ether }(nativeTokenContentToWrap, uriForWrappedToken, recipient); + + assertEq(weth.balanceOf(address(multiwrap)), 10 ether); } /** @@ -466,6 +512,33 @@ contract MultiwrapTest is BaseTest { multiwrap.wrap(emptyContent, uriForWrappedToken, recipient); } + function test_revert_wrap_nativeTokens_insufficientValueProvided_multipleInstances() public { + address recipient = address(0x123); + + ITokenBundle.Token[] memory nativeTokenContentToWrap = new ITokenBundle.Token[](2); + + vm.deal(address(tokenOwner), 100 ether); + vm.deal(address(multiwrap), 10 ether); + nativeTokenContentToWrap[0] = ITokenBundle.Token({ + assetContract: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, + tokenType: ITokenBundle.TokenType.ERC20, + tokenId: 0, + totalAmount: 10 ether + }); + nativeTokenContentToWrap[1] = ITokenBundle.Token({ + assetContract: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, + tokenType: ITokenBundle.TokenType.ERC20, + tokenId: 0, + totalAmount: 10 ether + }); + + vm.prank(address(tokenOwner)); + vm.expectRevert("msg.value != amount"); + multiwrap.wrap{ value: 10 ether }(nativeTokenContentToWrap, uriForWrappedToken, recipient); + + assertEq(address(multiwrap).balance, 10 ether); + } + /*/////////////////////////////////////////////////////////////// Unit tests: `unwrap` //////////////////////////////////////////////////////////////*/ @@ -496,6 +569,38 @@ contract MultiwrapTest is BaseTest { assertEq(contentsOfWrappedToken.length, 0); } + /** + * note: Testing state changes; wrapped token owner calls `unwrap` to unwrap native tokens. + */ + function test_state_unwrap_nativeTokens() public { + // ===== setup: wrap tokens ===== + uint256 expectedIdForWrappedToken = multiwrap.nextTokenIdToMint(); + address recipient = address(0x123); + + ITokenBundle.Token[] memory nativeTokenContentToWrap = new ITokenBundle.Token[](1); + + vm.deal(address(tokenOwner), 100 ether); + nativeTokenContentToWrap[0] = ITokenBundle.Token({ + assetContract: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, + tokenType: ITokenBundle.TokenType.ERC20, + tokenId: 0, + totalAmount: 10 ether + }); + + vm.prank(address(tokenOwner)); + multiwrap.wrap{ value: 10 ether }(nativeTokenContentToWrap, uriForWrappedToken, recipient); + + // ===== target test content ===== + + assertEq(address(recipient).balance, 0); + + vm.prank(recipient); + // it fails here and it shouldn't + multiwrap.unwrap(expectedIdForWrappedToken, recipient); + + assertEq(address(recipient).balance, 10 ether); + } + /** * note: Testing state changes; wrapped token owner calls `unwrap` to unwrap underlying tokens. */ @@ -592,7 +697,7 @@ contract MultiwrapTest is BaseTest { // ===== target test content ===== vm.prank(recipient); - vm.expectRevert("Multiwrap: wrapped NFT DNE."); + vm.expectRevert("wrapped NFT DNE."); multiwrap.unwrap(expectedIdForWrappedToken + 1, recipient); } @@ -607,7 +712,7 @@ contract MultiwrapTest is BaseTest { // ===== target test content ===== vm.prank(address(0x12)); - vm.expectRevert("Multiwrap: caller not approved for unwrapping."); + vm.expectRevert("caller not approved for unwrapping."); multiwrap.unwrap(expectedIdForWrappedToken, recipient); } @@ -625,7 +730,7 @@ contract MultiwrapTest is BaseTest { multiwrap.transferFrom(recipient, address(0x12), 0); vm.prank(recipient); - vm.expectRevert("Multiwrap: caller not approved for unwrapping."); + vm.expectRevert("caller not approved for unwrapping."); multiwrap.unwrap(expectedIdForWrappedToken, recipient); } diff --git a/src/test/Pack.t.sol b/src/test/Pack.t.sol index cc3385a4f..c86de8024 100644 --- a/src/test/Pack.t.sol +++ b/src/test/Pack.t.sol @@ -226,7 +226,9 @@ contract PackTest is BaseTest { vm.startPrank(deployer); pack.revokeRole(keccak256("ASSET_ROLE"), address(0)); for (uint256 i = 0; i < packContents.length; i += 1) { - pack.grantRole(keccak256("ASSET_ROLE"), packContents[i].assetContract); + if (!pack.hasRole(keccak256("ASSET_ROLE"), packContents[i].assetContract)) { + pack.grantRole(keccak256("ASSET_ROLE"), packContents[i].assetContract); + } } vm.stopPrank(); @@ -738,6 +740,7 @@ contract PackTest is BaseTest { function checkBalances(ITokenBundle.Token[] memory rewardUnits, address recipient) internal + view returns ( uint256 nativeTokenAmount, uint256 erc20Amount, diff --git a/src/test/SignatureDrop.t.sol b/src/test/SignatureDrop.t.sol index 7bbb9187a..d5d61e7f8 100644 --- a/src/test/SignatureDrop.t.sol +++ b/src/test/SignatureDrop.t.sol @@ -1,9 +1,11 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; -import { SignatureDrop } from "contracts/signature-drop/SignatureDrop.sol"; +import { SignatureDrop, IDropSinglePhase, IDelayedReveal, ISignatureMintERC721, ERC721AUpgradeable, IPermissions, ILazyMint } from "contracts/signature-drop/SignatureDrop.sol"; // Test imports +import "erc721a-upgradeable/contracts/IERC721AUpgradeable.sol"; +import "contracts/lib/TWStrings.sol"; import "./utils/BaseTest.sol"; import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; @@ -72,37 +74,37 @@ contract SignatureDropBenchmarkTest is BaseTest { _mintrequest.uid = bytes32(id); _signature = signMintRequest(_mintrequest, privateKey); - vm.startPrank(deployerSigner); + vm.startPrank(deployerSigner, deployerSigner); vm.warp(1000); erc20.approve(address(sigdrop), 1); } - function signMintRequest(SignatureDrop.MintRequest memory mintrequest, uint256 privateKey) + function signMintRequest(SignatureDrop.MintRequest memory _request, uint256 privateKey) internal returns (bytes memory) { bytes memory encodedRequest = abi.encode( typehashMintRequest, - mintrequest.to, - mintrequest.royaltyRecipient, - mintrequest.royaltyBps, - mintrequest.primarySaleRecipient, - keccak256(bytes(mintrequest.uri)), - mintrequest.quantity, - mintrequest.pricePerToken, - mintrequest.currency, - mintrequest.validityStartTimestamp, - mintrequest.validityEndTimestamp, - mintrequest.uid + _request.to, + _request.royaltyRecipient, + _request.royaltyBps, + _request.primarySaleRecipient, + keccak256(bytes(_request.uri)), + _request.quantity, + _request.pricePerToken, + _request.currency, + _request.validityStartTimestamp, + _request.validityEndTimestamp, + _request.uid ); bytes32 structHash = keccak256(encodedRequest); bytes32 typedDataHash = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, typedDataHash); - bytes memory signature = abi.encodePacked(r, s, v); + bytes memory sig = abi.encodePacked(r, s, v); - return signature; + return sig; } function test_benchmark_mintWithSignature() public { @@ -117,8 +119,8 @@ contract SignatureDropBenchmarkTest is BaseTest { contract SignatureDropTest is BaseTest { using StringsUpgradeable for uint256; - event TokensLazyMinted(uint256 startTokenId, uint256 endTokenId, string baseURI, bytes encryptedBaseURI); - event TokenURIRevealed(uint256 index, string revealedURI); + event TokensLazyMinted(uint256 indexed startTokenId, uint256 endTokenId, string baseURI, bytes encryptedBaseURI); + event TokenURIRevealed(uint256 indexed index, string revealedURI); event TokensMintedWithSignature( address indexed signer, address indexed mintedTo, @@ -155,6 +157,125 @@ contract SignatureDropTest is BaseTest { domainSeparator = keccak256(abi.encode(typehashEip712, nameHash, versionHash, block.chainid, address(sigdrop))); } + /*/////////////////////////////////////////////////////////////// + Unit tests: misc. + //////////////////////////////////////////////////////////////*/ + + /** + * note: Tests whether contract reverts when a non-holder renounces a role. + */ + function test_revert_nonHolder_renounceRole() public { + address caller = address(0x123); + bytes32 role = keccak256("MINTER_ROLE"); + + vm.prank(caller); + vm.expectRevert( + abi.encodePacked( + "Permissions: account ", + TWStrings.toHexString(uint160(caller), 20), + " is missing role ", + TWStrings.toHexString(uint256(role), 32) + ) + ); + + sigdrop.renounceRole(role, caller); + } + + /** + * note: Tests whether contract reverts when a role admin revokes a role for a non-holder. + */ + function test_revert_revokeRoleForNonHolder() public { + address target = address(0x123); + bytes32 role = keccak256("MINTER_ROLE"); + + vm.prank(deployerSigner); + vm.expectRevert( + abi.encodePacked( + "Permissions: account ", + TWStrings.toHexString(uint160(target), 20), + " is missing role ", + TWStrings.toHexString(uint256(role), 32) + ) + ); + + sigdrop.revokeRole(role, target); + } + + /** + * @dev Tests whether contract reverts when a role is granted to an existent role holder. + */ + function test_revert_grant_role_to_account_with_role() public { + bytes32 role = keccak256("ABC_ROLE"); + address receiver = getActor(0); + + vm.startPrank(deployerSigner); + + sigdrop.grantRole(role, receiver); + + vm.expectRevert(abi.encodeWithSelector(IPermissions.Permissions__CanOnlyGrantToNonHolders.selector, receiver)); + sigdrop.grantRole(role, receiver); + + vm.stopPrank(); + } + + /** + * @dev Tests whether role member count is incremented correctly. + */ + function test_member_count_incremented_properly_when_role_granted() public { + bytes32 role = keccak256("ABC_ROLE"); + address receiver = getActor(0); + + vm.startPrank(deployerSigner); + uint256 roleMemberCount = sigdrop.getRoleMemberCount(role); + + assertEq(roleMemberCount, 0); + + sigdrop.grantRole(role, receiver); + + assertEq(sigdrop.getRoleMemberCount(role), 1); + + vm.stopPrank(); + } + + function test_claimCondition_with_startTimestamp() public { + vm.warp(1); + + address receiver = getActor(0); + bytes32[] memory proofs = new bytes32[](0); + + SignatureDrop.AllowlistProof memory alp; + alp.proof = proofs; + + SignatureDrop.ClaimCondition[] memory conditions = new SignatureDrop.ClaimCondition[](1); + conditions[0].startTimestamp = 100; + conditions[0].maxClaimableSupply = 100; + conditions[0].quantityLimitPerTransaction = 100; + conditions[0].waitTimeInSecondsBetweenClaims = type(uint256).max; + + vm.prank(deployerSigner); + sigdrop.lazyMint(100, "ipfs://", ""); + + vm.prank(deployerSigner); + sigdrop.setClaimConditions(conditions[0], false); + + vm.warp(100); + vm.prank(getActor(4), getActor(4)); + sigdrop.claim(receiver, 1, address(0), 0, alp, ""); + + vm.warp(99); + vm.prank(getActor(5), getActor(5)); + vm.expectRevert( + abi.encodeWithSelector( + IDropSinglePhase.DropSinglePhase__CannotClaimYet.selector, + block.timestamp, + conditions[0].startTimestamp, + 0, + type(uint256).max + ) + ); + sigdrop.claim(receiver, 1, address(0), 0, alp, ""); + } + /*/////////////////////////////////////////////////////////////// Lazy Mint Tests //////////////////////////////////////////////////////////////*/ @@ -231,7 +352,7 @@ contract SignatureDropTest is BaseTest { sigdrop.lazyMint(100, "ipfs://", ""); - vm.expectRevert("No batch id for token."); + vm.expectRevert(abi.encodeWithSelector(ILazyMint.LazyMint__NoBatchIDForToken.selector, 100)); sigdrop.tokenURI(100); vm.stopPrank(); @@ -243,8 +364,8 @@ contract SignatureDropTest is BaseTest { function test_event_lazyMint_TokensLazyMinted() public { vm.startPrank(deployerSigner); - vm.expectEmit(false, false, false, true); - emit TokensLazyMinted(0, 100, "ipfs://", ""); + vm.expectEmit(true, false, false, true); + emit TokensLazyMinted(0, 99, "ipfs://", ""); sigdrop.lazyMint(100, "ipfs://", ""); vm.stopPrank(); @@ -325,8 +446,12 @@ contract SignatureDropTest is BaseTest { * note: Fuzz testing; a batch of tokens, and nextTokenIdToMint */ function test_fuzz_lazyMint_batchMintAndNextTokenIdToMint(uint256 x) public { + vm.assume(x > 0); vm.startPrank(deployerSigner); + if (x == 0) { + vm.expectRevert("Zero amount"); + } sigdrop.lazyMint(x, "ipfs://", ""); uint256 slot = stdstore.target(address(sigdrop)).sig("nextTokenIdToMint()").find(); @@ -405,7 +530,7 @@ contract SignatureDropTest is BaseTest { console.log(sigdrop.getBaseURICount()); sigdrop.lazyMint(100, "", encryptedURI); - vm.expectRevert("invalid index."); + vm.expectRevert(abi.encodeWithSelector(ILazyMint.LazyMint__InvalidIndex.selector, 2)); sigdrop.reveal(2, "key"); vm.stopPrank(); @@ -421,7 +546,7 @@ contract SignatureDropTest is BaseTest { sigdrop.lazyMint(100, "", encryptedURI); sigdrop.reveal(0, "key"); - vm.expectRevert("nothing to reveal."); + vm.expectRevert(abi.encodeWithSelector(IDelayedReveal.DelayedReveal__NothingToReveal.selector, 100)); sigdrop.reveal(0, "key"); vm.stopPrank(); @@ -451,7 +576,7 @@ contract SignatureDropTest is BaseTest { bytes memory encryptedURI = sigdrop.encryptDecrypt("ipfs://", "key"); sigdrop.lazyMint(100, "", encryptedURI); - vm.expectEmit(false, false, false, true); + vm.expectEmit(true, false, false, true); emit TokenURIRevealed(0, "ipfs://"); sigdrop.reveal(0, "key"); @@ -571,7 +696,7 @@ contract SignatureDropTest is BaseTest { sigdrop.mintWithSignature(mintrequest, signature); signature = signMintRequest(mintrequest, 4321); - vm.expectRevert("Invalid request"); + vm.expectRevert(abi.encodeWithSelector(ISignatureMintERC721.SignatureMintERC721__InvalidRequest.selector)); sigdrop.mintWithSignature(mintrequest, signature); } @@ -598,7 +723,9 @@ contract SignatureDropTest is BaseTest { bytes memory signature = signMintRequest(mintrequest, privateKey); vm.warp(1000); - vm.expectRevert("not enough minted tokens."); + vm.expectRevert( + abi.encodeWithSelector(SignatureDrop.SignatureDrop__NotEnoughMintedTokens.selector, 0, mintrequest.quantity) + ); sigdrop.mintWithSignature(mintrequest, signature); } @@ -627,7 +754,7 @@ contract SignatureDropTest is BaseTest { bytes memory signature = signMintRequest(mintrequest, privateKey); vm.startPrank(address(deployerSigner)); vm.warp(mintrequest.validityStartTimestamp); - vm.expectRevert("must send total price."); + vm.expectRevert(abi.encodeWithSelector(SignatureDrop.SignatureDrop__MustSendTotalPrice.selector, 2, 1)); sigdrop.mintWithSignature{ value: 2 }(mintrequest, signature); vm.stopPrank(); } @@ -675,7 +802,7 @@ contract SignatureDropTest is BaseTest { erc20.balanceOf(deployerSigner) ); - vm.expectRevert(abi.encodeWithSignature("OwnerQueryForNonexistentToken()")); + vm.expectRevert(abi.encodeWithSelector(IERC721AUpgradeable.OwnerQueryForNonexistentToken.selector)); owner = sigdrop.ownerOf(1); } } @@ -759,7 +886,15 @@ contract SignatureDropTest is BaseTest { vm.prank(getActor(5), getActor(5)); sigdrop.claim(receiver, 1, address(0), 0, alp, ""); - vm.expectRevert("cannot claim."); + vm.expectRevert( + abi.encodeWithSelector( + IDropSinglePhase.DropSinglePhase__CannotClaimYet.selector, + block.timestamp, + 0, + 1, + type(uint256).max + ) + ); vm.prank(getActor(5), getActor(5)); sigdrop.claim(receiver, 1, address(0), 0, alp, ""); } @@ -786,7 +921,7 @@ contract SignatureDropTest is BaseTest { vm.prank(deployerSigner); sigdrop.setClaimConditions(conditions[0], false); - vm.expectRevert("not enough minted tokens."); + vm.expectRevert(abi.encodeWithSelector(SignatureDrop.SignatureDrop__NotEnoughMintedTokens.selector, 0, 101)); vm.prank(getActor(6), getActor(6)); sigdrop.claim(receiver, 101, address(0), 0, alp, ""); } @@ -816,19 +951,59 @@ contract SignatureDropTest is BaseTest { vm.prank(getActor(5), getActor(5)); sigdrop.claim(receiver, 100, address(0), 0, alp, ""); - vm.expectRevert("exceed max claimable supply."); + vm.expectRevert( + abi.encodeWithSelector(IDropSinglePhase.DropSinglePhase__ExceedMaxClaimableSupply.selector, 100, 100) + ); vm.prank(getActor(6), getActor(6)); sigdrop.claim(receiver, 1, address(0), 0, alp, ""); } + /** + * note: Testing quantity limit restriction when no allowlist present. + */ + function test_fuzz_claim_noAllowlist(uint256 x) public { + vm.assume(x != 0); + vm.warp(1); + + address receiver = getActor(0); + bytes32[] memory proofs = new bytes32[](0); + + SignatureDrop.AllowlistProof memory alp; + alp.proof = proofs; + alp.maxQuantityInAllowlist = x; + + SignatureDrop.ClaimCondition[] memory conditions = new SignatureDrop.ClaimCondition[](1); + conditions[0].maxClaimableSupply = 500; + conditions[0].quantityLimitPerTransaction = 100; + conditions[0].waitTimeInSecondsBetweenClaims = type(uint256).max; + + vm.prank(deployerSigner); + sigdrop.lazyMint(500, "ipfs://", bytes("")); + + vm.prank(deployerSigner); + sigdrop.setClaimConditions(conditions[0], false); + + vm.prank(getActor(5), getActor(5)); + vm.expectRevert(abi.encodeWithSelector(IDropSinglePhase.DropSinglePhase__InvalidQuantity.selector)); + sigdrop.claim(receiver, 101, address(0), 0, alp, ""); + + vm.prank(deployerSigner); + sigdrop.setClaimConditions(conditions[0], true); + + vm.prank(getActor(5), getActor(5)); + vm.expectRevert(abi.encodeWithSelector(IDropSinglePhase.DropSinglePhase__InvalidQuantity.selector)); + sigdrop.claim(receiver, 101, address(0), 0, alp, ""); + } + /** * note: Testing revert condition; can't claim if not in whitelist. */ function test_revert_claimCondition_merkleProof() public { - string[] memory inputs = new string[](2); + string[] memory inputs = new string[](3); inputs[0] = "node"; inputs[1] = "src/test/scripts/generateRoot.ts"; + inputs[2] = "1"; bytes memory result = vm.ffi(inputs); bytes32 root = abi.decode(result, (bytes32)); @@ -843,6 +1018,7 @@ contract SignatureDropTest is BaseTest { SignatureDrop.AllowlistProof memory alp; alp.proof = proofs; + alp.maxQuantityInAllowlist = 1; SignatureDrop.ClaimCondition[] memory conditions = new SignatureDrop.ClaimCondition[](1); conditions[0].maxClaimableSupply = 100; @@ -856,12 +1032,12 @@ contract SignatureDropTest is BaseTest { sigdrop.setClaimConditions(conditions[0], false); // vm.prank(getActor(5), getActor(5)); - vm.prank(receiver); - sigdrop.claim(receiver, 100, address(0), 0, alp, ""); + vm.prank(receiver, receiver); + sigdrop.claim(receiver, 1, address(0), 0, alp, ""); - vm.prank(address(4)); - vm.expectRevert("not in whitelist."); - sigdrop.claim(receiver, 100, address(0), 0, alp, ""); + vm.prank(address(4), address(4)); + vm.expectRevert(abi.encodeWithSelector(IDropSinglePhase.DropSinglePhase__NotInWhitelist.selector)); + sigdrop.claim(receiver, 1, address(0), 0, alp, ""); } /** @@ -897,6 +1073,41 @@ contract SignatureDropTest is BaseTest { sigdrop.claim(receiver, 1, address(0), 0, alp, ""); } + /*/////////////////////////////////////////////////////////////// + Miscellaneous + //////////////////////////////////////////////////////////////*/ + function test_breaking_reveal() public { + address attacker = getActor(0); + bytes memory encryptedURI = sigdrop.encryptDecrypt("ipfs://", "key"); + + vm.prank(deployerSigner); + sigdrop.lazyMint(100, "", encryptedURI); + + uint256 batchId = sigdrop.getBatchIdAtIndex(0); + vm.prank(attacker); + sigdrop.getRevealURI(batchId, "wrong keyy"); + + vm.prank(deployerSigner); + sigdrop.reveal(0, "key"); + } + + function test_delayedReveal_withNewLazyMintedEmptyBatch() public { + vm.startPrank(deployerSigner); + + bytes memory encryptedURI = sigdrop.encryptDecrypt("ipfs://", "key"); + sigdrop.lazyMint(100, "", encryptedURI); + sigdrop.reveal(0, "key"); + + string memory uri = sigdrop.tokenURI(1); + assertEq(uri, string(abi.encodePacked("ipfs://", "1"))); + + bytes memory newEncryptedURI = sigdrop.encryptDecrypt("ipfs://secret", "key"); + vm.expectRevert(abi.encodeWithSelector(SignatureDrop.SignatureDrop__ZeroAmount.selector)); + sigdrop.lazyMint(0, "", newEncryptedURI); + + vm.stopPrank(); + } + /*/////////////////////////////////////////////////////////////// Reentrancy related Tests //////////////////////////////////////////////////////////////*/ diff --git a/src/test/drop/DropERC721.t.sol b/src/test/drop/DropERC721.t.sol index ef6b85dfc..6000fd596 100644 --- a/src/test/drop/DropERC721.t.sol +++ b/src/test/drop/DropERC721.t.sol @@ -13,6 +13,8 @@ contract SubExploitContract is ERC721Holder, ERC1155Holder { // using Strings for uint256; + // using Strings for uint256; + constructor(address _drop) { drop = DropERC721(_drop); master = payable(msg.sender);