From 05cfdcf3975d4f9718ea9a4b47db82470ae922ed Mon Sep 17 00:00:00 2001 From: Rohan2407 Date: Wed, 17 May 2023 09:25:43 +0530 Subject: [PATCH 1/4] forge install: openzeppelin-contracts v4.8.3 --- .gitmodules | 4 ++++ lib/openzeppelin-contracts | 1 + 2 files changed, 5 insertions(+) create mode 160000 lib/openzeppelin-contracts diff --git a/.gitmodules b/.gitmodules index cf07d41f..d3df2720 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,7 @@ [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std +[submodule "lib/openzeppelin-contracts"] + path = lib/openzeppelin-contracts + url = https://github.com/OpenZeppelin/openzeppelin-contracts + branch = v4.8.3 diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts new file mode 160000 index 00000000..0a25c194 --- /dev/null +++ b/lib/openzeppelin-contracts @@ -0,0 +1 @@ +Subproject commit 0a25c1940ca220686588c4af3ec526f725fe2582 From 0b9fea8dfe8c965a8ac1128279e81b99e1b34986 Mon Sep 17 00:00:00 2001 From: Rohan2407 Date: Wed, 17 May 2023 09:36:50 +0530 Subject: [PATCH 2/4] added manifold contracts zora --- contracts/manifold/FallbackRegistry.sol | 52 + contracts/manifold/IRoyaltyEngineV1.sol | 42 + contracts/manifold/IRoyaltyRegistry.sol | 45 + contracts/manifold/RoyaltyEngineV1.sol | 425 + contracts/manifold/RoyaltyRegistry.sol | 165 + contracts/manifold/libraries/BytesLibrary.sol | 45 + .../manifold/libraries/SuperRareContracts.sol | 9 + .../manifold/overrides/IFallbackRegistry.sol | 12 + .../IMultiReceiverRoyaltyOverride.sol | 48 + .../manifold/overrides/IRoyaltyOverride.sol | 47 + .../manifold/overrides/IRoyaltySplitter.sol | 24 + .../MultiReceiverRoyaltyOverrideCloneable.sol | 42 + .../MultiReceiverRoyaltyOverrideCore.sol | 148 + .../overrides/RoyaltyOverrideCloneable.sol | 33 + .../overrides/RoyaltyOverrideCore.sol | 88 + .../overrides/RoyaltyOverrideFactory.sol | 94 + .../manifold/overrides/RoyaltySplitter.sol | 194 + contracts/manifold/specs/IArtBlocks.sol | 11 + .../manifold/specs/IArtBlocksOverride.sol | 18 + contracts/manifold/specs/IDigitalax.sol | 17 + contracts/manifold/specs/IEIP2981.sol | 15 + contracts/manifold/specs/IFoundation.sol | 20 + contracts/manifold/specs/IKODAV2Override.sol | 28 + contracts/manifold/specs/IManifold.sol | 19 + contracts/manifold/specs/INiftyGateway.sol | 20 + contracts/manifold/specs/IRarible.sol | 27 + contracts/manifold/specs/ISuperRare.sol | 33 + contracts/manifold/specs/IZoraOverride.sol | 55 + package-lock.json | 6856 +++++++++++++++++ yarn.lock | 3731 +++++---- 30 files changed, 10733 insertions(+), 1630 deletions(-) create mode 100644 contracts/manifold/FallbackRegistry.sol create mode 100644 contracts/manifold/IRoyaltyEngineV1.sol create mode 100644 contracts/manifold/IRoyaltyRegistry.sol create mode 100644 contracts/manifold/RoyaltyEngineV1.sol create mode 100644 contracts/manifold/RoyaltyRegistry.sol create mode 100644 contracts/manifold/libraries/BytesLibrary.sol create mode 100644 contracts/manifold/libraries/SuperRareContracts.sol create mode 100644 contracts/manifold/overrides/IFallbackRegistry.sol create mode 100644 contracts/manifold/overrides/IMultiReceiverRoyaltyOverride.sol create mode 100644 contracts/manifold/overrides/IRoyaltyOverride.sol create mode 100644 contracts/manifold/overrides/IRoyaltySplitter.sol create mode 100644 contracts/manifold/overrides/MultiReceiverRoyaltyOverrideCloneable.sol create mode 100644 contracts/manifold/overrides/MultiReceiverRoyaltyOverrideCore.sol create mode 100644 contracts/manifold/overrides/RoyaltyOverrideCloneable.sol create mode 100644 contracts/manifold/overrides/RoyaltyOverrideCore.sol create mode 100644 contracts/manifold/overrides/RoyaltyOverrideFactory.sol create mode 100644 contracts/manifold/overrides/RoyaltySplitter.sol create mode 100644 contracts/manifold/specs/IArtBlocks.sol create mode 100644 contracts/manifold/specs/IArtBlocksOverride.sol create mode 100644 contracts/manifold/specs/IDigitalax.sol create mode 100644 contracts/manifold/specs/IEIP2981.sol create mode 100644 contracts/manifold/specs/IFoundation.sol create mode 100644 contracts/manifold/specs/IKODAV2Override.sol create mode 100644 contracts/manifold/specs/IManifold.sol create mode 100644 contracts/manifold/specs/INiftyGateway.sol create mode 100644 contracts/manifold/specs/IRarible.sol create mode 100644 contracts/manifold/specs/ISuperRare.sol create mode 100644 contracts/manifold/specs/IZoraOverride.sol create mode 100644 package-lock.json diff --git a/contracts/manifold/FallbackRegistry.sol b/contracts/manifold/FallbackRegistry.sol new file mode 100644 index 00000000..3a63ddd6 --- /dev/null +++ b/contracts/manifold/FallbackRegistry.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import {Recipient} from "./overrides/IRoyaltySplitter.sol"; +import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import {IFallbackRegistry} from "./overrides/IFallbackRegistry.sol"; + +contract FallbackRegistry is IFallbackRegistry, Ownable2Step { + struct TokenFallback { + address tokenAddress; + Recipient[] recipients; + } + + mapping(address => Recipient[]) fallbacks; + + constructor(address initialOwner) { + _transferOwnership(initialOwner); + } + + function setFallback(address tokenAddress, Recipient[] calldata _recipients) public onlyOwner { + Recipient[] storage recipients = fallbacks[tokenAddress]; + uint256 recipientsLength = _recipients.length; + ///@solidity memory-safe-assembly + assembly { + // overwrite length directly rather than deleting and then updating it each time we push new values + // this means if the new array is shorter than the old ones, those slots will stay dirty, but they + // should not be able to be accessed due to the new length + sstore(recipients.slot, recipientsLength) + } + for (uint256 i; i < recipientsLength; ) { + recipients[i] = _recipients[i]; + unchecked { + ++i; + } + } + } + + function setFallbacks(TokenFallback[] calldata bundle) external onlyOwner { + uint256 bundleLength = bundle.length; + for (uint256 i = 0; i < bundleLength; ) { + TokenFallback calldata tokenFallback = bundle[i]; + setFallback(tokenFallback.tokenAddress, tokenFallback.recipients); + unchecked { + ++i; + } + } + } + + function getRecipients(address tokenAddress) external view returns (Recipient[] memory) { + return fallbacks[tokenAddress]; + } +} diff --git a/contracts/manifold/IRoyaltyEngineV1.sol b/contracts/manifold/IRoyaltyEngineV1.sol new file mode 100644 index 00000000..819427c5 --- /dev/null +++ b/contracts/manifold/IRoyaltyEngineV1.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/// @author: manifold.xyz + +import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + +/** + * @dev Lookup engine interface + */ +interface IRoyaltyEngineV1 is IERC165 { + /** + * Get the royalty for a given token (address, id) and value amount. Does not cache the bps/amounts. Caches the spec for a given token address + * + * @param tokenAddress - The address of the token + * @param tokenId - The id of the token + * @param value - The value you wish to get the royalty of + * + * returns Two arrays of equal length, royalty recipients and the corresponding amount each recipient should get + */ + function getRoyalty( + address tokenAddress, + uint256 tokenId, + uint256 value + ) external returns (address payable[] memory recipients, uint256[] memory amounts); + + /** + * View only version of getRoyalty + * + * @param tokenAddress - The address of the token + * @param tokenId - The id of the token + * @param value - The value you wish to get the royalty of + * + * returns Two arrays of equal length, royalty recipients and the corresponding amount each recipient should get + */ + function getRoyaltyView( + address tokenAddress, + uint256 tokenId, + uint256 value + ) external view returns (address payable[] memory recipients, uint256[] memory amounts); +} diff --git a/contracts/manifold/IRoyaltyRegistry.sol b/contracts/manifold/IRoyaltyRegistry.sol new file mode 100644 index 00000000..5c04200b --- /dev/null +++ b/contracts/manifold/IRoyaltyRegistry.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/// @author: manifold.xyz + +import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + +/** + * @dev Royalty registry interface + */ +interface IRoyaltyRegistry is IERC165 { + event RoyaltyOverride(address owner, address tokenAddress, address royaltyAddress); + + /** + * Override the location of where to look up royalty information for a given token contract. + * Allows for backwards compatibility and implementation of royalty logic for contracts that did not previously support them. + * + * @param tokenAddress - The token address you wish to override + * @param royaltyAddress - The royalty override address + */ + function setRoyaltyLookupAddress(address tokenAddress, address royaltyAddress) external returns (bool); + + /** + * Returns royalty address location. Returns the tokenAddress by default, or the override if it exists + * + * @param tokenAddress - The token address you are looking up the royalty for + */ + function getRoyaltyLookupAddress(address tokenAddress) external view returns (address); + + /** + * Returns the token address that an overrideAddress is set for. + * Note: will not be accurate if the override was created before this function was added. + * + * @param overrideAddress - The override address you are looking up the token for + */ + function getOverrideLookupTokenAddress(address overrideAddress) external view returns (address); + + /** + * Whether or not the message sender can override the royalty address for the given token address + * + * @param tokenAddress - The token address you are looking up the royalty for + */ + function overrideAllowed(address tokenAddress) external view returns (bool); +} diff --git a/contracts/manifold/RoyaltyEngineV1.sol b/contracts/manifold/RoyaltyEngineV1.sol new file mode 100644 index 00000000..00893ca6 --- /dev/null +++ b/contracts/manifold/RoyaltyEngineV1.sol @@ -0,0 +1,425 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/// @author: manifold.xyz + +import {ERC165, IERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import {ERC165Checker} from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {AddressUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; + +import {SuperRareContracts} from "./libraries/SuperRareContracts.sol"; + +import {IManifold} from "./specs/IManifold.sol"; +import {IRaribleV1, IRaribleV2} from "./specs/IRarible.sol"; +import {IFoundation} from "./specs/IFoundation.sol"; +import {ISuperRareRegistry} from "./specs/ISuperRare.sol"; +import {IEIP2981} from "./specs/IEIP2981.sol"; +import {IZoraOverride} from "./specs/IZoraOverride.sol"; +import {IArtBlocksOverride} from "./specs/IArtBlocksOverride.sol"; +import {IKODAV2Override} from "./specs/IKODAV2Override.sol"; +import {IRoyaltyEngineV1} from "./IRoyaltyEngineV1.sol"; +import {IRoyaltyRegistry} from "./IRoyaltyRegistry.sol"; +import {IRoyaltySplitter, Recipient} from "./overrides/IRoyaltySplitter.sol"; +import {IFallbackRegistry} from "./overrides/IFallbackRegistry.sol"; + +/** + * @dev Engine to lookup royalty configurations + */ + +contract RoyaltyEngineV1 is ERC165, OwnableUpgradeable, IRoyaltyEngineV1 { + using AddressUpgradeable for address; + + // Use int16 for specs to support future spec additions + // When we add a spec, we also decrement the NONE value + // Anything > NONE and <= NOT_CONFIGURED is considered not configured + int16 private constant NONE = -1; + int16 private constant NOT_CONFIGURED = 0; + int16 private constant MANIFOLD = 1; + int16 private constant RARIBLEV1 = 2; + int16 private constant RARIBLEV2 = 3; + int16 private constant FOUNDATION = 4; + int16 private constant EIP2981 = 5; + int16 private constant SUPERRARE = 6; + int16 private constant ZORA = 7; + int16 private constant ARTBLOCKS = 8; + int16 private constant KNOWNORIGINV2 = 9; + int16 private constant ROYALTY_SPLITTER = 10; + int16 private constant FALLBACK = type(int16).max; + + mapping(address => int16) _specCache; + + address public royaltyRegistry; + IFallbackRegistry public immutable FALLBACK_REGISTRY; + + constructor(address fallbackRegistry) { + FALLBACK_REGISTRY = IFallbackRegistry(fallbackRegistry); + } + + function initialize(address _initialOwner, address royaltyRegistry_) public initializer { + _transferOwnership(_initialOwner); + require(ERC165Checker.supportsInterface(royaltyRegistry_, type(IRoyaltyRegistry).interfaceId)); + royaltyRegistry = royaltyRegistry_; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return interfaceId == type(IRoyaltyEngineV1).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Invalidate the cached spec (useful for situations where tooken royalty implementation changes to a different spec) + */ + function invalidateCachedRoyaltySpec(address tokenAddress) public { + address royaltyAddress = IRoyaltyRegistry(royaltyRegistry).getRoyaltyLookupAddress(tokenAddress); + delete _specCache[royaltyAddress]; + } + + /** + * @dev View function to get the cached spec of a token + */ + function getCachedRoyaltySpec(address tokenAddress) public view returns (int16) { + address royaltyAddress = IRoyaltyRegistry(royaltyRegistry).getRoyaltyLookupAddress(tokenAddress); + return _specCache[royaltyAddress]; + } + + /** + * @dev See {IRoyaltyEngineV1-getRoyalty} + */ + function getRoyalty( + address tokenAddress, + uint256 tokenId, + uint256 value + ) public override returns (address payable[] memory recipients, uint256[] memory amounts) { + // External call to limit gas + try this._getRoyaltyAndSpec{gas: 100000}(tokenAddress, tokenId, value) returns ( + address payable[] memory _recipients, + uint256[] memory _amounts, + int16 spec, + address royaltyAddress, + bool addToCache + ) { + if (addToCache) _specCache[royaltyAddress] = spec; + return (_recipients, _amounts); + } catch { + revert("Invalid royalty amount"); + } + } + + /** + * @dev See {IRoyaltyEngineV1-getRoyaltyView}. + */ + function getRoyaltyView( + address tokenAddress, + uint256 tokenId, + uint256 value + ) public view override returns (address payable[] memory recipients, uint256[] memory amounts) { + // External call to limit gas + try this._getRoyaltyAndSpec{gas: 100000}(tokenAddress, tokenId, value) returns ( + address payable[] memory _recipients, + uint256[] memory _amounts, + int16, + address, + bool + ) { + return (_recipients, _amounts); + } catch { + revert("Invalid royalty amount"); + } + } + + /** + * @dev Get the royalty and royalty spec for a given token + * + * returns recipients array, amounts array, royalty spec, royalty address, whether or not to add to cache + */ + function _getRoyaltyAndSpec( + address tokenAddress, + uint256 tokenId, + uint256 value + ) + external + view + returns ( + address payable[] memory recipients, + uint256[] memory amounts, + int16 spec, + address royaltyAddress, + bool addToCache + ) + { + require(msg.sender == address(this), "Only Engine"); + + royaltyAddress = IRoyaltyRegistry(royaltyRegistry).getRoyaltyLookupAddress(tokenAddress); + spec = _specCache[royaltyAddress]; + + if (spec <= NOT_CONFIGURED && spec > NONE) { + // No spec configured yet, so we need to detect the spec + addToCache = true; + + // SuperRare handling + if (tokenAddress == SuperRareContracts.SUPERRARE_V1 || tokenAddress == SuperRareContracts.SUPERRARE_V2) { + try ISuperRareRegistry(SuperRareContracts.SUPERRARE_REGISTRY).tokenCreator(tokenAddress, tokenId) returns (address payable creator) { + try ISuperRareRegistry(SuperRareContracts.SUPERRARE_REGISTRY).calculateRoyaltyFee(tokenAddress, tokenId, value) returns ( + uint256 amount + ) { + recipients = new address payable[](1); + amounts = new uint256[](1); + recipients[0] = creator; + amounts[0] = amount; + return (recipients, amounts, SUPERRARE, royaltyAddress, addToCache); + } catch {} + } catch {} + } + try IEIP2981(royaltyAddress).royaltyInfo(tokenId, value) returns (address recipient, uint256 amount) { + require(amount < value, "Invalid royalty amount"); + uint32 recipientSize; + assembly { + recipientSize := extcodesize(recipient) + } + if (recipientSize > 0) { + try IRoyaltySplitter(recipient).getRecipients() returns (Recipient[] memory splitRecipients) { + recipients = new address payable[](splitRecipients.length); + amounts = new uint256[](splitRecipients.length); + uint256 sum = 0; + uint256 splitRecipientsLength = splitRecipients.length; + for (uint256 i = 0; i < splitRecipientsLength; ) { + Recipient memory splitRecipient = splitRecipients[i]; + recipients[i] = payable(splitRecipient.recipient); + uint256 splitAmount = (splitRecipient.bps * amount) / 10000; + amounts[i] = splitAmount; + sum += splitAmount; + unchecked { + ++i; + } + } + // sum can be less than amount, otherwise small-value listings can break + require(sum <= amount, "Invalid split"); + + return (recipients, amounts, ROYALTY_SPLITTER, royaltyAddress, addToCache); + } catch {} + } + // Supports EIP2981. Return amounts + recipients = new address payable[](1); + amounts = new uint256[](1); + recipients[0] = payable(recipient); + amounts[0] = amount; + return (recipients, amounts, EIP2981, royaltyAddress, addToCache); + } catch {} + try IManifold(royaltyAddress).getRoyalties(tokenId) returns (address payable[] memory recipients_, uint256[] memory bps) { + // Supports manifold interface. Compute amounts + require(recipients_.length == bps.length); + return (recipients_, _computeAmounts(value, bps), MANIFOLD, royaltyAddress, addToCache); + } catch {} + try IRaribleV2(royaltyAddress).getRaribleV2Royalties(tokenId) returns (IRaribleV2.Part[] memory royalties) { + // Supports rarible v2 interface. Compute amounts + recipients = new address payable[](royalties.length); + amounts = new uint256[](royalties.length); + uint256 totalAmount; + for (uint256 i = 0; i < royalties.length; i++) { + recipients[i] = royalties[i].account; + amounts[i] = (value * royalties[i].value) / 10000; + totalAmount += amounts[i]; + } + require(totalAmount < value, "Invalid royalty amount"); + return (recipients, amounts, RARIBLEV2, royaltyAddress, addToCache); + } catch {} + try IRaribleV1(royaltyAddress).getFeeRecipients(tokenId) returns (address payable[] memory recipients_) { + // Supports rarible v1 interface. Compute amounts + recipients_ = IRaribleV1(royaltyAddress).getFeeRecipients(tokenId); + try IRaribleV1(royaltyAddress).getFeeBps(tokenId) returns (uint256[] memory bps) { + require(recipients_.length == bps.length); + return (recipients_, _computeAmounts(value, bps), RARIBLEV1, royaltyAddress, addToCache); + } catch {} + } catch {} + try IFoundation(royaltyAddress).getFees(tokenId) returns (address payable[] memory recipients_, uint256[] memory bps) { + // Supports foundation interface. Compute amounts + require(recipients_.length == bps.length); + return (recipients_, _computeAmounts(value, bps), FOUNDATION, royaltyAddress, addToCache); + } catch {} + try IZoraOverride(royaltyAddress).convertBidShares(tokenAddress, tokenId) returns ( + address payable[] memory recipients_, + uint256[] memory bps + ) { + // Support Zora override + require(recipients_.length == bps.length); + return (recipients_, _computeAmounts(value, bps), ZORA, royaltyAddress, addToCache); + } catch {} + try IArtBlocksOverride(royaltyAddress).getRoyalties(tokenAddress, tokenId) returns ( + address payable[] memory recipients_, + uint256[] memory bps + ) { + // Support Art Blocks override + require(recipients_.length == bps.length); + return (recipients_, _computeAmounts(value, bps), ARTBLOCKS, royaltyAddress, addToCache); + } catch {} + try IKODAV2Override(royaltyAddress).getKODAV2RoyaltyInfo(tokenAddress, tokenId, value) returns ( + address payable[] memory _recipients, + uint256[] memory _amounts + ) { + // Support KODA V2 override + require(_recipients.length == _amounts.length); + return (_recipients, _amounts, KNOWNORIGINV2, royaltyAddress, addToCache); + } catch {} + + try FALLBACK_REGISTRY.getRecipients(tokenAddress) returns (Recipient[] memory _recipients) { + uint256 recipientsLength = _recipients.length; + if (recipientsLength > 0) { + return _calculateFallback(_recipients, recipientsLength, value, royaltyAddress, addToCache); + } + } catch {} + + // No supported royalties configured + return (recipients, amounts, NONE, royaltyAddress, addToCache); + } else { + // Spec exists, just execute the appropriate one + addToCache = false; + if (spec == NONE) { + return (recipients, amounts, spec, royaltyAddress, addToCache); + } else if (spec == FALLBACK) { + Recipient[] memory _recipients = FALLBACK_REGISTRY.getRecipients(tokenAddress); + return _calculateFallback(_recipients, _recipients.length, value, royaltyAddress, addToCache); + } else if (spec == MANIFOLD) { + // Manifold spec + uint256[] memory bps; + (recipients, bps) = IManifold(royaltyAddress).getRoyalties(tokenId); + require(recipients.length == bps.length); + return (recipients, _computeAmounts(value, bps), spec, royaltyAddress, addToCache); + } else if (spec == RARIBLEV2) { + // Rarible v2 spec + IRaribleV2.Part[] memory royalties; + royalties = IRaribleV2(royaltyAddress).getRaribleV2Royalties(tokenId); + recipients = new address payable[](royalties.length); + amounts = new uint256[](royalties.length); + uint256 totalAmount; + for (uint256 i = 0; i < royalties.length; i++) { + recipients[i] = royalties[i].account; + amounts[i] = (value * royalties[i].value) / 10000; + totalAmount += amounts[i]; + } + require(totalAmount < value, "Invalid royalty amount"); + return (recipients, amounts, spec, royaltyAddress, addToCache); + } else if (spec == RARIBLEV1) { + // Rarible v1 spec + uint256[] memory bps; + recipients = IRaribleV1(royaltyAddress).getFeeRecipients(tokenId); + bps = IRaribleV1(royaltyAddress).getFeeBps(tokenId); + require(recipients.length == bps.length); + return (recipients, _computeAmounts(value, bps), spec, royaltyAddress, addToCache); + } else if (spec == FOUNDATION) { + // Foundation spec + uint256[] memory bps; + (recipients, bps) = IFoundation(royaltyAddress).getFees(tokenId); + require(recipients.length == bps.length); + return (recipients, _computeAmounts(value, bps), spec, royaltyAddress, addToCache); + } else if (spec == EIP2981 || spec == ROYALTY_SPLITTER) { + // EIP2981 spec + (address recipient, uint256 amount) = IEIP2981(royaltyAddress).royaltyInfo(tokenId, value); + require(amount < value, "Invalid royalty amount"); + if (spec == ROYALTY_SPLITTER) { + Recipient[] memory splitRecipients = IRoyaltySplitter(recipient).getRecipients(); + recipients = new address payable[](splitRecipients.length); + amounts = new uint256[](splitRecipients.length); + uint256 sum = 0; + uint256 splitRecipientsLength = splitRecipients.length; + for (uint256 i = 0; i < splitRecipientsLength; ) { + Recipient memory splitRecipient = splitRecipients[i]; + recipients[i] = payable(splitRecipient.recipient); + uint256 splitAmount = (splitRecipient.bps * amount) / 10000; + amounts[i] = splitAmount; + sum += splitAmount; + unchecked { + ++i; + } + } + // sum can be less than amount, otherwise small-value listings can break + require(sum <= value, "Invalid split"); + + return (recipients, amounts, spec, royaltyAddress, addToCache); + } + recipients = new address payable[](1); + amounts = new uint256[](1); + recipients[0] = payable(recipient); + amounts[0] = amount; + return (recipients, amounts, spec, royaltyAddress, addToCache); + } else if (spec == SUPERRARE) { + // SUPERRARE spec + address payable creator = ISuperRareRegistry(SuperRareContracts.SUPERRARE_REGISTRY).tokenCreator(tokenAddress, tokenId); + uint256 amount = ISuperRareRegistry(SuperRareContracts.SUPERRARE_REGISTRY).calculateRoyaltyFee(tokenAddress, tokenId, value); + recipients = new address payable[](1); + amounts = new uint256[](1); + recipients[0] = creator; + amounts[0] = amount; + return (recipients, amounts, spec, royaltyAddress, addToCache); + } else if (spec == ZORA) { + // Zora spec + uint256[] memory bps; + (recipients, bps) = IZoraOverride(royaltyAddress).convertBidShares(tokenAddress, tokenId); + require(recipients.length == bps.length); + return (recipients, _computeAmounts(value, bps), spec, royaltyAddress, addToCache); + } else if (spec == ARTBLOCKS) { + // Art Blocks spec + uint256[] memory bps; + (recipients, bps) = IArtBlocksOverride(royaltyAddress).getRoyalties(tokenAddress, tokenId); + require(recipients.length == bps.length); + return (recipients, _computeAmounts(value, bps), spec, royaltyAddress, addToCache); + } else if (spec == KNOWNORIGINV2) { + // KnownOrigin.io V2 spec (V3 falls under EIP2981) + (recipients, amounts) = IKODAV2Override(royaltyAddress).getKODAV2RoyaltyInfo(tokenAddress, tokenId, value); + require(recipients.length == amounts.length); + return (recipients, amounts, spec, royaltyAddress, addToCache); + } + } + } + + function _calculateFallback( + Recipient[] memory _recipients, + uint256 recipientsLength, + uint256 value, + address royaltyAddress, + bool addToCache + ) + internal + pure + returns ( + address payable[] memory recipients, + uint256[] memory amounts, + int16 spec, + address _royaltyAddress, + bool _addToCache + ) + { + recipients = new address payable[](recipientsLength); + amounts = new uint256[](recipientsLength); + uint256 totalAmount; + for (uint256 i = 0; i < recipientsLength; ) { + Recipient memory recipient = _recipients[i]; + recipients[i] = payable(recipient.recipient); + uint256 amount = (value * recipient.bps) / 10_000; + amounts[i] = amount; + totalAmount += amount; + unchecked { + ++i; + } + } + require(totalAmount < value, "Invalid royalty amount"); + return (recipients, amounts, FALLBACK, royaltyAddress, addToCache); + } + + /** + * Compute royalty amounts + */ + function _computeAmounts(uint256 value, uint256[] memory bps) private pure returns (uint256[] memory amounts) { + amounts = new uint256[](bps.length); + uint256 totalAmount; + for (uint256 i = 0; i < bps.length; i++) { + amounts[i] = (value * bps[i]) / 10000; + totalAmount += amounts[i]; + } + require(totalAmount < value, "Invalid royalty amount"); + return amounts; + } +} diff --git a/contracts/manifold/RoyaltyRegistry.sol b/contracts/manifold/RoyaltyRegistry.sol new file mode 100644 index 00000000..c12a21fc --- /dev/null +++ b/contracts/manifold/RoyaltyRegistry.sol @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/// @author: manifold.xyz + +import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; +import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/access/IAccessControlUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; +import "@manifoldxyz/libraries-solidity/contracts/access/IAdminControl.sol"; + +import "./IRoyaltyRegistry.sol"; +import "./specs/INiftyGateway.sol"; +import "./specs/IFoundation.sol"; +import "./specs/IDigitalax.sol"; +import "./specs/IArtBlocks.sol"; + +/** + * @dev Registry to lookup royalty configurations + */ +contract RoyaltyRegistry is ERC165, OwnableUpgradeable, IRoyaltyRegistry { + using AddressUpgradeable for address; + + address public immutable OVERRIDE_FACTORY; + + /** + * @notice Constructor arg allows efficient lookup of override factory for single-tx overrides. + * However, this means the RoyaltyRegistry will need to be upgraded if the override factory is changed. + */ + constructor(address overrideFactory) { + OVERRIDE_FACTORY = overrideFactory; + } + + // Override addresses + mapping(address => address) private _overrides; + mapping(address => address) private _overrideLookupToTokenContract; + + function initialize(address _initialOwner) public initializer { + _transferOwnership(_initialOwner); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return interfaceId == type(IRoyaltyRegistry).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IRegistry-getRoyaltyLookupAddress}. + */ + function getRoyaltyLookupAddress(address tokenAddress) external view override returns (address) { + address override_ = _overrides[tokenAddress]; + if (override_ != address(0)) { + return override_; + } + return tokenAddress; + } + + /** + * @dev See {IRegistry-getOverrideTokenAddress}. + */ + function getOverrideLookupTokenAddress(address overrideAddress) external view override returns (address) { + return _overrideLookupToTokenContract[overrideAddress]; + } + + /** + * @dev See {IRegistry-setRoyaltyLookupAddress}. + */ + function setRoyaltyLookupAddress(address tokenAddress, address royaltyLookupAddress) public override returns (bool) { + require(tokenAddress.isContract() && (royaltyLookupAddress.isContract() || royaltyLookupAddress == address(0)), "Invalid input"); + require(overrideAllowed(tokenAddress), "Permission denied"); + // look up existing override, if any + address existingOverride = _overrides[tokenAddress]; + if (existingOverride != address(0)) { + // delete existing override reverse-lookup + _overrideLookupToTokenContract[existingOverride] = address(0); + } + _overrideLookupToTokenContract[royaltyLookupAddress] = tokenAddress; + // set new override and reverse-lookup + _overrides[tokenAddress] = royaltyLookupAddress; + + emit RoyaltyOverride(_msgSender(), tokenAddress, royaltyLookupAddress); + return true; + } + + /** + * @dev See {IRegistry-overrideAllowed}. + */ + function overrideAllowed(address tokenAddress) public view override returns (bool) { + if (owner() == _msgSender()) return true; + + if (ERC165Checker.supportsInterface(tokenAddress, type(IAdminControl).interfaceId) && IAdminControl(tokenAddress).isAdmin(_msgSender())) { + return true; + } + + try OwnableUpgradeable(tokenAddress).owner() returns (address owner) { + if (owner == _msgSender()) return true; + + if (owner.isContract()) { + try OwnableUpgradeable(owner).owner() returns (address passThroughOwner) { + if (passThroughOwner == _msgSender()) return true; + } catch {} + } + } catch {} + + try IAccessControlUpgradeable(tokenAddress).hasRole(0x00, _msgSender()) returns (bool hasRole) { + if (hasRole) return true; + } catch {} + + // Nifty Gateway overrides + try INiftyBuilderInstance(tokenAddress).niftyRegistryContract() returns (address niftyRegistry) { + try INiftyRegistry(niftyRegistry).isValidNiftySender(_msgSender()) returns (bool valid) { + return valid; + } catch {} + } catch {} + + // OpenSea overrides + // Tokens already support Ownable + + // Foundation overrides + try IFoundationTreasuryNode(tokenAddress).getFoundationTreasury() returns (address payable foundationTreasury) { + try IFoundationTreasury(foundationTreasury).isAdmin(_msgSender()) returns (bool isAdmin) { + return isAdmin; + } catch {} + } catch {} + + // DIGITALAX overrides + try IDigitalax(tokenAddress).accessControls() returns (address externalAccessControls) { + try IDigitalaxAccessControls(externalAccessControls).hasAdminRole(_msgSender()) returns (bool hasRole) { + if (hasRole) return true; + } catch {} + } catch {} + + // Art Blocks overrides + try IArtBlocks(tokenAddress).admin() returns (address admin) { + if (admin == _msgSender()) return true; + } catch {} + + // Superrare overrides + // Tokens and registry already support Ownable + + // Rarible overrides + // Tokens already support Ownable + + return false; + } + + function _msgSender() internal view virtual override(ContextUpgradeable) returns (address) { + if (msg.sender == OVERRIDE_FACTORY) { + address relayedSender; + ///@solidity memory-safe-assembly + assembly { + // the factory appends the original msg.sender as last the word of calldata, which we can read using + // calldataload + relayedSender := calldataload(sub(calldatasize(), 0x20)) + } + return relayedSender; + } + // otherwise return msg.sender as normal + return msg.sender; + } +} diff --git a/contracts/manifold/libraries/BytesLibrary.sol b/contracts/manifold/libraries/BytesLibrary.sol new file mode 100644 index 00000000..efb9cc42 --- /dev/null +++ b/contracts/manifold/libraries/BytesLibrary.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 + +pragma solidity ^0.8.0; + +/** + * @notice A library for manipulation of byte arrays. + */ +library BytesLibrary { + /** + * @dev Replace the address at the given location in a byte array if the contents at that location + * match the expected address. + */ + function replaceAtIf( + bytes memory data, + uint256 startLocation, + address expectedAddress, + address newAddress + ) internal pure { + bytes memory expectedData = abi.encodePacked(expectedAddress); + bytes memory newData = abi.encodePacked(newAddress); + // An address is 20 bytes long + for (uint256 i = 0; i < 20; i++) { + uint256 dataLocation = startLocation + i; + require(data[dataLocation] == expectedData[i], "Bytes: Data provided does not include the expectedAddress"); + data[dataLocation] = newData[i]; + } + } + + /** + * @dev Checks if the call data starts with the given function signature. + */ + function startsWith(bytes memory callData, bytes4 functionSig) internal pure returns (bool) { + // A signature is 4 bytes long + if (callData.length < 4) { + return false; + } + for (uint256 i = 0; i < 4; i++) { + if (callData[i] != functionSig[i]) { + return false; + } + } + + return true; + } +} diff --git a/contracts/manifold/libraries/SuperRareContracts.sol b/contracts/manifold/libraries/SuperRareContracts.sol new file mode 100644 index 00000000..eaf489bc --- /dev/null +++ b/contracts/manifold/libraries/SuperRareContracts.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +library SuperRareContracts { + address public constant SUPERRARE_REGISTRY = 0x17B0C8564E53f22364A6C8de6F7ca5CE9BEa4e5D; + address public constant SUPERRARE_V1 = 0x41A322b28D0fF354040e2CbC676F0320d8c8850d; + address public constant SUPERRARE_V2 = 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0; +} diff --git a/contracts/manifold/overrides/IFallbackRegistry.sol b/contracts/manifold/overrides/IFallbackRegistry.sol new file mode 100644 index 00000000..dda6e88b --- /dev/null +++ b/contracts/manifold/overrides/IFallbackRegistry.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import {Recipient} from "./IRoyaltySplitter.sol"; + +interface IFallbackRegistry { + /** + * @dev Get total recipients for token fees. Note that recipient bps is of gross amount, not share of fee amount, + * ie, recipients' BPS will not sum to 10_000, but to the total fee BPS for an order. + */ + function getRecipients(address tokenAddress) external view returns (Recipient[] memory); +} diff --git a/contracts/manifold/overrides/IMultiReceiverRoyaltyOverride.sol b/contracts/manifold/overrides/IMultiReceiverRoyaltyOverride.sol new file mode 100644 index 00000000..7a22725b --- /dev/null +++ b/contracts/manifold/overrides/IMultiReceiverRoyaltyOverride.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/// @author: manifold.xyz + +import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import "./IRoyaltySplitter.sol"; + +/** + * Multi-receiver EIP2981 reference override implementation + */ +interface IEIP2981MultiReceiverRoyaltyOverride is IERC165 { + event TokenRoyaltyRemoved(uint256 tokenId); + event TokenRoyaltySet(uint256 tokenId, uint16 royaltyBPS, Recipient[] recipients); + event DefaultRoyaltySet(uint16 royaltyBPS, Recipient[] recipients); + + struct TokenRoyaltyConfig { + uint256 tokenId; + uint16 royaltyBPS; + Recipient[] recipients; + } + + /** + * @dev Set per token royalties. Passing a recipient of address(0) will delete any existing configuration + */ + function setTokenRoyalties(TokenRoyaltyConfig[] calldata royalties) external; + + /** + * @dev Get all token royalty configurations + */ + function getTokenRoyalties() external view returns (TokenRoyaltyConfig[] memory); + + /** + * @dev Get the default royalty + */ + function getDefaultRoyalty() external view returns (uint16 bps, Recipient[] memory); + + /** + * @dev Set a default royalty configuration. Will be used if no token specific configuration is set + */ + function setDefaultRoyalty(uint16 bps, Recipient[] calldata recipients) external; + + /** + * @dev Helper function to get all splits contracts + */ + function getAllSplits() external view returns (address payable[] memory); +} diff --git a/contracts/manifold/overrides/IRoyaltyOverride.sol b/contracts/manifold/overrides/IRoyaltyOverride.sol new file mode 100644 index 00000000..f62ebb18 --- /dev/null +++ b/contracts/manifold/overrides/IRoyaltyOverride.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/// @author: manifold.xyz + +import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + +/** + * Simple EIP2981 reference override implementation + */ +interface IEIP2981RoyaltyOverride is IERC165 { + event TokenRoyaltyRemoved(uint256 tokenId); + event TokenRoyaltySet(uint256 tokenId, address recipient, uint16 bps); + event DefaultRoyaltySet(address recipient, uint16 bps); + + struct TokenRoyalty { + address recipient; + uint16 bps; + } + + struct TokenRoyaltyConfig { + uint256 tokenId; + address recipient; + uint16 bps; + } + + /** + * @dev Set per token royalties. Passing a recipient of address(0) will delete any existing configuration + */ + function setTokenRoyalties(TokenRoyaltyConfig[] calldata royalties) external; + + /** + * @dev Get the number of token specific overrides. Used to enumerate over all configurations + */ + function getTokenRoyaltiesCount() external view returns (uint256); + + /** + * @dev Get a token royalty configuration by index. Use in conjunction with getTokenRoyaltiesCount to get all per token configurations + */ + function getTokenRoyaltyByIndex(uint256 index) external view returns (TokenRoyaltyConfig memory); + + /** + * @dev Set a default royalty configuration. Will be used if no token specific configuration is set + */ + function setDefaultRoyalty(TokenRoyalty calldata royalty) external; +} diff --git a/contracts/manifold/overrides/IRoyaltySplitter.sol b/contracts/manifold/overrides/IRoyaltySplitter.sol new file mode 100644 index 00000000..97860038 --- /dev/null +++ b/contracts/manifold/overrides/IRoyaltySplitter.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/// @author: manifold.xyz + +import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + +struct Recipient { + address payable recipient; + uint16 bps; +} + +interface IRoyaltySplitter is IERC165 { + /** + * @dev Set the splitter recipients. Total bps must total 10000. + */ + function setRecipients(Recipient[] calldata recipients) external; + + /** + * @dev Get the splitter recipients; + */ + function getRecipients() external view returns (Recipient[] memory); +} diff --git a/contracts/manifold/overrides/MultiReceiverRoyaltyOverrideCloneable.sol b/contracts/manifold/overrides/MultiReceiverRoyaltyOverrideCloneable.sol new file mode 100644 index 00000000..ed1913e8 --- /dev/null +++ b/contracts/manifold/overrides/MultiReceiverRoyaltyOverrideCloneable.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/// @author: manifold.xyz + +import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; + +import "./MultiReceiverRoyaltyOverrideCore.sol"; +import "./IRoyaltySplitter.sol"; +import "../IRoyaltyRegistry.sol"; + +/** + * Simple EIP2981 reference override implementation + */ +contract EIP2981MultiReceiverRoyaltyOverrideCloneable is EIP2981MultiReceiverRoyaltyMultiReceiverOverrideCore, OwnableUpgradeable { + function initialize( + address payable royaltySplitterCloneable, + uint16 defaultBps, + Recipient[] memory defaultRecipients, + address initialOwner + ) public initializer { + _transferOwnership(initialOwner); + _royaltySplitterCloneable = royaltySplitterCloneable; + // Initialize with default royalties + _setDefaultRoyalty(defaultBps, defaultRecipients); + } + + /** + * @dev See {IEIP2981MultiReceiverRoyaltyOverride-setTokenRoyalties}. + */ + function setTokenRoyalties(TokenRoyaltyConfig[] calldata royaltyConfigs) external override onlyOwner { + _setTokenRoyalties(royaltyConfigs); + } + + /** + * @dev See {IEIP2981MultiReceiverRoyaltyOverride-setDefaultRoyalty}. + */ + function setDefaultRoyalty(uint16 bps, Recipient[] calldata recipients) external override onlyOwner { + _setDefaultRoyalty(bps, recipients); + } +} diff --git a/contracts/manifold/overrides/MultiReceiverRoyaltyOverrideCore.sol b/contracts/manifold/overrides/MultiReceiverRoyaltyOverrideCore.sol new file mode 100644 index 00000000..5ed04ab7 --- /dev/null +++ b/contracts/manifold/overrides/MultiReceiverRoyaltyOverrideCore.sol @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/// @author: manifold.xyz + +import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import "@openzeppelin/contracts/proxy/Clones.sol"; + +import "./IMultiReceiverRoyaltyOverride.sol"; +import "./RoyaltySplitter.sol"; +import "./IRoyaltySplitter.sol"; +import "../specs/IEIP2981.sol"; + +/** + * Multi-receiver EIP2981 reference override implementation + */ +abstract contract EIP2981MultiReceiverRoyaltyMultiReceiverOverrideCore is IEIP2981, IEIP2981MultiReceiverRoyaltyOverride, ERC165 { + uint16 private _defaultRoyaltyBPS; + address payable private _defaultRoyaltySplitter; + + mapping(uint256 => address payable) private _tokenRoyaltiesSplitter; + mapping(uint256 => uint16) private _tokenRoyaltiesBPS; + uint256[] private _tokensWithRoyalties; + + // Address of cloneable splitter contract + address internal _royaltySplitterCloneable; + + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IEIP2981).interfaceId || + interfaceId == type(IEIP2981MultiReceiverRoyaltyOverride).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev Sets token royalties. When you override this in the implementation contract + * ensure that you access restrict it to the contract owner or admin + */ + function _setTokenRoyalties(TokenRoyaltyConfig[] memory royaltyConfigs) internal { + for (uint256 i; i < royaltyConfigs.length; i++) { + TokenRoyaltyConfig memory royaltyConfig = royaltyConfigs[i]; + require(royaltyConfig.royaltyBPS < 10000, "Invalid bps"); + Recipient[] memory recipients = royaltyConfig.recipients; + address payable splitterAddress = _tokenRoyaltiesSplitter[royaltyConfig.tokenId]; + if (recipients.length == 0) { + if (splitterAddress != address(0)) { + IRoyaltySplitter(splitterAddress).setRecipients(recipients); + } + delete _tokenRoyaltiesBPS[royaltyConfig.tokenId]; + emit TokenRoyaltyRemoved(royaltyConfig.tokenId); + } else { + if (splitterAddress == address(0)) { + splitterAddress = payable(Clones.clone(_royaltySplitterCloneable)); + RoyaltySplitter(splitterAddress).initialize(recipients); + _tokenRoyaltiesSplitter[royaltyConfig.tokenId] = splitterAddress; + _tokensWithRoyalties.push(royaltyConfig.tokenId); + } else { + IRoyaltySplitter(splitterAddress).setRecipients(recipients); + } + _tokenRoyaltiesBPS[royaltyConfig.tokenId] = royaltyConfig.royaltyBPS; + emit TokenRoyaltySet(royaltyConfig.tokenId, royaltyConfig.royaltyBPS, recipients); + } + } + } + + /** + * @dev Sets default royalty. When you override this in the implementation contract + * ensure that you access restrict it to the contract owner or admin + */ + function _setDefaultRoyalty(uint16 bps, Recipient[] memory recipients) internal { + require(bps < 10000, "Invalid bps"); + if (_defaultRoyaltySplitter == address(0)) { + _defaultRoyaltySplitter = payable(Clones.clone(_royaltySplitterCloneable)); + RoyaltySplitter(_defaultRoyaltySplitter).initialize(recipients); + } else { + IRoyaltySplitter(_defaultRoyaltySplitter).setRecipients(recipients); + } + _defaultRoyaltyBPS = bps; + emit DefaultRoyaltySet(bps, recipients); + } + + /** + * @dev See {IEIP2981MultiReceiverRoyaltyOverride-getTokenRoyalties}. + */ + function getTokenRoyalties() external view override returns (TokenRoyaltyConfig[] memory royaltyConfigs) { + royaltyConfigs = new TokenRoyaltyConfig[](_tokensWithRoyalties.length); + for (uint256 i; i < _tokensWithRoyalties.length; ++i) { + TokenRoyaltyConfig memory royaltyConfig; + uint256 tokenId = _tokensWithRoyalties[i]; + address splitterAddress = _tokenRoyaltiesSplitter[tokenId]; + if (splitterAddress != address(0)) { + royaltyConfig.recipients = IRoyaltySplitter(splitterAddress).getRecipients(); + } + royaltyConfig.tokenId = tokenId; + royaltyConfig.royaltyBPS = _tokenRoyaltiesBPS[tokenId]; + royaltyConfigs[i] = royaltyConfig; + } + } + + /** + * @dev See {IEIP2981MultiReceiverRoyaltyOverride-getDefaultRoyalty}. + */ + function getDefaultRoyalty() external view override returns (uint16 bps, Recipient[] memory recipients) { + if (_defaultRoyaltySplitter != address(0)) { + recipients = IRoyaltySplitter(_defaultRoyaltySplitter).getRecipients(); + } + return (_defaultRoyaltyBPS, recipients); + } + + /** + * @dev See {IEIP2981MultiReceiverRoyaltyOverride-royaltyInfo}. + */ + function royaltyInfo(uint256 tokenId, uint256 value) public view override returns (address, uint256) { + if (_tokenRoyaltiesSplitter[tokenId] != address(0)) { + return (_tokenRoyaltiesSplitter[tokenId], (value * _tokenRoyaltiesBPS[tokenId]) / 10000); + } + if (_defaultRoyaltySplitter != address(0) && _defaultRoyaltyBPS != 0) { + return (_defaultRoyaltySplitter, (value * _defaultRoyaltyBPS) / 10000); + } + return (address(0), 0); + } + + /** + * @dev See {IEIP2981MultiReceiverRoyaltyOverride-getAllSplits}. + */ + function getAllSplits() external view override returns (address payable[] memory splits) { + uint256 startingIndex; + uint256 endingIndex = _tokensWithRoyalties.length; + if (_defaultRoyaltySplitter != address(0)) { + splits = new address payable[](1 + _tokensWithRoyalties.length); + splits[0] = _defaultRoyaltySplitter; + startingIndex = 1; + ++endingIndex; + } else { + // unreachable in practice + splits = new address payable[](_tokensWithRoyalties.length); + } + for (uint256 i = startingIndex; i < endingIndex; ++i) { + splits[i] = _tokenRoyaltiesSplitter[_tokensWithRoyalties[i - startingIndex]]; + } + } + + function getRecipients() public view returns (Recipient[] memory) { + return RoyaltySplitter(_defaultRoyaltySplitter).getRecipients(); + } +} diff --git a/contracts/manifold/overrides/RoyaltyOverrideCloneable.sol b/contracts/manifold/overrides/RoyaltyOverrideCloneable.sol new file mode 100644 index 00000000..34daa243 --- /dev/null +++ b/contracts/manifold/overrides/RoyaltyOverrideCloneable.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/// @author: manifold.xyz + +import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; + +import "./RoyaltyOverrideCore.sol"; + +/** + * Simple EIP2981 reference override implementation + */ +contract EIP2981RoyaltyOverrideCloneable is EIP2981RoyaltyOverrideCore, OwnableUpgradeable { + function initialize(TokenRoyalty calldata _defaultRoyalty, address initialOwner) public initializer { + _transferOwnership(initialOwner); + _setDefaultRoyalty(_defaultRoyalty); + } + + /** + * @dev See {IEIP2981RoyaltyOverride-setTokenRoyalties}. + */ + function setTokenRoyalties(TokenRoyaltyConfig[] calldata royaltyConfigs) external override onlyOwner { + _setTokenRoyalties(royaltyConfigs); + } + + /** + * @dev See {IEIP2981RoyaltyOverride-setDefaultRoyalty}. + */ + function setDefaultRoyalty(TokenRoyalty calldata royalty) external override onlyOwner { + _setDefaultRoyalty(royalty); + } +} diff --git a/contracts/manifold/overrides/RoyaltyOverrideCore.sol b/contracts/manifold/overrides/RoyaltyOverrideCore.sol new file mode 100644 index 00000000..251b173d --- /dev/null +++ b/contracts/manifold/overrides/RoyaltyOverrideCore.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/// @author: manifold.xyz + +import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; + +import "./IRoyaltyOverride.sol"; +import "../specs/IEIP2981.sol"; + +/** + * Simple EIP2981 reference override implementation + */ +abstract contract EIP2981RoyaltyOverrideCore is IEIP2981, IEIP2981RoyaltyOverride, ERC165 { + using EnumerableSet for EnumerableSet.UintSet; + + TokenRoyalty public defaultRoyalty; + mapping(uint256 => TokenRoyalty) private _tokenRoyalties; + EnumerableSet.UintSet private _tokensWithRoyalties; + + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IEIP2981).interfaceId || + interfaceId == type(IEIP2981RoyaltyOverride).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev Sets token royalties. When you override this in the implementation contract + * ensure that you access restrict it to the contract owner or admin + */ + function _setTokenRoyalties(TokenRoyaltyConfig[] memory royaltyConfigs) internal { + for (uint256 i = 0; i < royaltyConfigs.length; i++) { + TokenRoyaltyConfig memory royaltyConfig = royaltyConfigs[i]; + require(royaltyConfig.bps < 10000, "Invalid bps"); + if (royaltyConfig.recipient == address(0)) { + delete _tokenRoyalties[royaltyConfig.tokenId]; + _tokensWithRoyalties.remove(royaltyConfig.tokenId); + emit TokenRoyaltyRemoved(royaltyConfig.tokenId); + } else { + _tokenRoyalties[royaltyConfig.tokenId] = TokenRoyalty(royaltyConfig.recipient, royaltyConfig.bps); + _tokensWithRoyalties.add(royaltyConfig.tokenId); + emit TokenRoyaltySet(royaltyConfig.tokenId, royaltyConfig.recipient, royaltyConfig.bps); + } + } + } + + /** + * @dev Sets default royalty. When you override this in the implementation contract + * ensure that you access restrict it to the contract owner or admin + */ + function _setDefaultRoyalty(TokenRoyalty memory royalty) internal { + require(royalty.bps < 10000, "Invalid bps"); + defaultRoyalty = TokenRoyalty(royalty.recipient, royalty.bps); + emit DefaultRoyaltySet(royalty.recipient, royalty.bps); + } + + /** + * @dev See {IEIP2981RoyaltyOverride-getTokenRoyaltiesCount}. + */ + function getTokenRoyaltiesCount() external view override returns (uint256) { + return _tokensWithRoyalties.length(); + } + + /** + * @dev See {IEIP2981RoyaltyOverride-getTokenRoyaltyByIndex}. + */ + function getTokenRoyaltyByIndex(uint256 index) external view override returns (TokenRoyaltyConfig memory) { + uint256 tokenId = _tokensWithRoyalties.at(index); + TokenRoyalty memory royalty = _tokenRoyalties[tokenId]; + return TokenRoyaltyConfig(tokenId, royalty.recipient, royalty.bps); + } + + /** + * @dev See {IEIP2981RoyaltyOverride-royaltyInfo}. + */ + function royaltyInfo(uint256 tokenId, uint256 value) public view override returns (address, uint256) { + if (_tokenRoyalties[tokenId].recipient != address(0)) { + return (_tokenRoyalties[tokenId].recipient, (value * _tokenRoyalties[tokenId].bps) / 10000); + } + if (defaultRoyalty.recipient != address(0) && defaultRoyalty.bps != 0) { + return (defaultRoyalty.recipient, (value * defaultRoyalty.bps) / 10000); + } + return (address(0), 0); + } +} diff --git a/contracts/manifold/overrides/RoyaltyOverrideFactory.sol b/contracts/manifold/overrides/RoyaltyOverrideFactory.sol new file mode 100644 index 00000000..eae1aaac --- /dev/null +++ b/contracts/manifold/overrides/RoyaltyOverrideFactory.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/// @author: manifold.xyz + +import "@openzeppelin/contracts/proxy/Clones.sol"; +import {EIP2981RoyaltyOverrideCloneable} from "./RoyaltyOverrideCloneable.sol"; +import {EIP2981MultiReceiverRoyaltyOverrideCloneable} from "./MultiReceiverRoyaltyOverrideCloneable.sol"; +import {IRoyaltyRegistry} from "../IRoyaltyRegistry.sol"; +import {Recipient} from "./IRoyaltySplitter.sol"; + +/** + * Clone Factory for EIP2981 reference override implementation + */ +contract EIP2981RoyaltyOverrideFactory { + address public immutable SINGLE_RECIPIENT_ORIGIN_ADDRESS; + address public immutable MULTI_RECIPIENT_ORIGIN_ADDRESS; + address payable public immutable ROYALTY_SPLITTER_ORIGIN_ADDRESS; + + error InvalidRoyaltyRegistryAddress(); + + uint256 constant INVALID_ROYALTY_REGISTRY_ADDRESS_SELECTOR = 0x1c491d3; + + event EIP2981RoyaltyOverrideCreated(address newEIP2981RoyaltyOverride); + + constructor( + address singleOrigin, + address multiOrigin, + address payable royaltySplitterOrigin + ) { + SINGLE_RECIPIENT_ORIGIN_ADDRESS = singleOrigin; + MULTI_RECIPIENT_ORIGIN_ADDRESS = multiOrigin; + ROYALTY_SPLITTER_ORIGIN_ADDRESS = royaltySplitterOrigin; + } + + function createOverrideAndRegister( + address royaltyRegistry, + address tokenAddress, + EIP2981RoyaltyOverrideCloneable.TokenRoyalty calldata defaultRoyalty + ) public returns (address) { + address clone = Clones.clone(SINGLE_RECIPIENT_ORIGIN_ADDRESS); + EIP2981RoyaltyOverrideCloneable(clone).initialize(defaultRoyalty, msg.sender); + emit EIP2981RoyaltyOverrideCreated(clone); + registerOverride(royaltyRegistry, tokenAddress, clone); + return clone; + } + + function createOverrideAndRegister( + address royaltyRegistry, + address tokenAddress, + uint16 defaultBps, + Recipient[] calldata defaultRecipients + ) public returns (address) { + address clone = Clones.clone(MULTI_RECIPIENT_ORIGIN_ADDRESS); + EIP2981MultiReceiverRoyaltyOverrideCloneable(clone).initialize(ROYALTY_SPLITTER_ORIGIN_ADDRESS, defaultBps, defaultRecipients, msg.sender); + emit EIP2981RoyaltyOverrideCreated(clone); + registerOverride(royaltyRegistry, tokenAddress, clone); + return clone; + } + + function registerOverride( + address royaltyRegistry, + address tokenAddress, + address lookupAddress + ) internal { + // encode setRoyaltyLookupAddress call with tokenAddress and lookupAddress and also append msg.sender to calldata. + // Including the original msg.sender allows the registry to securely verify the caller is the owner of the token + bytes memory data = abi.encodeWithSelector(IRoyaltyRegistry.setRoyaltyLookupAddress.selector, tokenAddress, lookupAddress, msg.sender); + + // check success and return data, and bubble up original revert reason if call was unsuccessful + ///@solidity memory-safe-assembly + assembly { + // clear first word of scratch space, where we will store one word of returndata + // if the call results in no returndata is available, this would not be overwritten otherwise + mstore(0, 0) + let success := call(gas(), royaltyRegistry, 0, add(data, 0x20), mload(data), 0, 0x20) + + // check if call succeeded + if iszero(success) { + // copy all of returndata to memory starting at 0; we don't have to worry about dirtying memory since + // we are reverting. + returndatacopy(0, 0, returndatasize()) + revert(0, returndatasize()) + } + // check if returned boolean is true, since a successful call does not guarantee a successful execution + let returned := mload(0) + if iszero(eq(returned, 1)) { + mstore(0, INVALID_ROYALTY_REGISTRY_ADDRESS_SELECTOR) + revert(0x1c, 4) + } + } + } +} diff --git a/contracts/manifold/overrides/RoyaltySplitter.sol b/contracts/manifold/overrides/RoyaltySplitter.sol new file mode 100644 index 00000000..07c7f010 --- /dev/null +++ b/contracts/manifold/overrides/RoyaltySplitter.sol @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 + +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; +import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import "@openzeppelin/contracts/utils/math/SafeMath.sol"; +import "@openzeppelin/contracts/proxy/Clones.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "../libraries/BytesLibrary.sol"; +import "./IRoyaltySplitter.sol"; + +interface IERC20Approve { + function approve(address spender, uint256 amount) external returns (bool); + + function increaseAllowance(address spender, uint256 amount) external returns (bool); +} + +/** + * Cloneable and configurable royalty splitter contract + */ +contract RoyaltySplitter is Initializable, OwnableUpgradeable, IRoyaltySplitter, ERC165 { + using BytesLibrary for bytes; + using AddressUpgradeable for address payable; + using AddressUpgradeable for address; + using SafeMath for uint256; + + uint256 internal constant BASIS_POINTS = 10000; + uint256 constant IERC20_APPROVE_SELECTOR = 0x095ea7b300000000000000000000000000000000000000000000000000000000; + uint256 constant SELECTOR_MASK = 0xffffffff00000000000000000000000000000000000000000000000000000000; + + Recipient[] private _recipients; + + event PercentSplitCreated(address indexed contractAddress); + event PercentSplitShare(address indexed recipient, uint256 percentInBasisPoints); + event ETHTransferred(address indexed account, uint256 amount); + event ERC20Transferred(address indexed erc20Contract, address indexed account, uint256 amount); + + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return interfaceId == type(IRoyaltySplitter).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Requires that the msg.sender is one of the recipients in this split. + */ + modifier onlyRecipient() { + for (uint256 i = 0; i < _recipients.length; i++) { + if (_recipients[i].recipient == msg.sender) { + _; + return; + } + } + revert("Split: Can only be called by one of the recipients"); + } + + /** + * @notice Called once to configure the contract after the initial deployment. + * @dev This will be called by `createSplit` after deploying the proxy so it should never be called directly. + */ + function initialize(Recipient[] calldata recipients) public initializer { + __Ownable_init(); + _setRecipients(recipients); + } + + /** + * @dev Set the splitter recipients. Total bps must total 10000. + */ + function setRecipients(Recipient[] calldata recipients) external override onlyOwner { + _setRecipients(recipients); + } + + function _setRecipients(Recipient[] calldata recipients) private { + delete _recipients; + if (recipients.length == 0) { + return; + } + uint256 totalBPS; + for (uint256 i; i < recipients.length; ++i) { + totalBPS += recipients[i].bps; + _recipients.push(recipients[i]); + } + require(totalBPS == BASIS_POINTS, "Total bps must be 10000"); + } + + /** + * @dev Get the splitter recipients; + */ + function getRecipients() external view override returns (Recipient[] memory) { + return _recipients; + } + + /** + * @notice Forwards any ETH received to the recipients in this split. + * @dev Each recipient increases the gas required to split + * and contract recipients may significantly increase the gas required. + */ + receive() external payable { + _splitETH(msg.value); + } + + /** + * @notice Allows any ETH stored by the contract to be split among recipients. + * @dev Normally ETH is forwarded as it comes in, but a balance in this contract + * is possible if it was sent before the contract was created or if self destruct was used. + */ + function splitETH() public { + _splitETH(address(this).balance); + } + + function _splitETH(uint256 value) internal { + if (value > 0) { + uint256 totalSent; + uint256 amountToSend; + unchecked { + for (uint256 i = _recipients.length - 1; i > 0; i--) { + Recipient memory recipient = _recipients[i]; + amountToSend = (value * recipient.bps) / BASIS_POINTS; + totalSent += amountToSend; + recipient.recipient.sendValue(amountToSend); + emit ETHTransferred(recipient.recipient, amountToSend); + } + // Favor the 1st recipient if there are any rounding issues + amountToSend = value - totalSent; + } + _recipients[0].recipient.sendValue(amountToSend); + emit ETHTransferred(_recipients[0].recipient, amountToSend); + } + } + + /** + * @notice Anyone can call this function to split all available tokens at the provided address between the recipients. + * @dev This contract is built to split ETH payments. The ability to attempt to split ERC20 tokens is here + * just in case tokens were also sent so that they don't get locked forever in the contract. + */ + function splitERC20Tokens(IERC20 erc20Contract) public { + require(_splitERC20Tokens(erc20Contract), "Split: ERC20 split failed"); + } + + function _splitERC20Tokens(IERC20 erc20Contract) internal returns (bool) { + try erc20Contract.balanceOf(address(this)) returns (uint256 balance) { + if (balance == 0) { + return false; + } + uint256 amountToSend; + uint256 totalSent; + unchecked { + for (uint256 i = _recipients.length - 1; i > 0; i--) { + Recipient memory recipient = _recipients[i]; + bool success; + (success, amountToSend) = balance.tryMul(recipient.bps); + + amountToSend /= BASIS_POINTS; + totalSent += amountToSend; + try erc20Contract.transfer(recipient.recipient, amountToSend) { + emit ERC20Transferred(address(erc20Contract), recipient.recipient, amountToSend); + } catch { + return false; + } + } + // Favor the 1st recipient if there are any rounding issues + amountToSend = balance - totalSent; + } + try erc20Contract.transfer(_recipients[0].recipient, amountToSend) { + emit ERC20Transferred(address(erc20Contract), _recipients[0].recipient, amountToSend); + } catch { + return false; + } + return true; + } catch { + return false; + } + } + + /** + * @notice Allows the split recipients to make an arbitrary contract call. + * @dev This is provided to allow recovering from unexpected scenarios, + * such as receiving an NFT at this address. + * + * It will first attempt a fair split of ERC20 tokens before proceeding. + * + * This contract is built to split ETH payments. The ability to attempt to make other calls is here + * just in case other assets were also sent so that they don't get locked forever in the contract. + */ + function proxyCall(address payable target, bytes calldata callData) external onlyRecipient { + require( + !callData.startsWith(IERC20Approve.approve.selector) && !callData.startsWith(IERC20Approve.increaseAllowance.selector), + "Split: ERC20 tokens must be split" + ); + try this.splitERC20Tokens(IERC20(target)) {} catch {} + target.functionCall(callData); + } +} diff --git a/contracts/manifold/specs/IArtBlocks.sol b/contracts/manifold/specs/IArtBlocks.sol new file mode 100644 index 00000000..11ff8449 --- /dev/null +++ b/contracts/manifold/specs/IArtBlocks.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Art Blocks nfts + */ +interface IArtBlocks { + // document getter function of public variable + function admin() external view returns (address); +} diff --git a/contracts/manifold/specs/IArtBlocksOverride.sol b/contracts/manifold/specs/IArtBlocksOverride.sol new file mode 100644 index 00000000..2f17fbf1 --- /dev/null +++ b/contracts/manifold/specs/IArtBlocksOverride.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * Interface for an Art Blocks override + */ +interface IArtBlocksOverride { + /** + * @dev Get royalites of a token at a given tokenAddress. + * Returns array of receivers and basisPoints. + * + * bytes4(keccak256('getRoyalties(address,uint256)')) == 0x9ca7dc7a + * + * => 0x9ca7dc7a = 0x9ca7dc7a + */ + function getRoyalties(address tokenAddress, uint256 tokenId) external view returns (address payable[] memory, uint256[] memory); +} diff --git a/contracts/manifold/specs/IDigitalax.sol b/contracts/manifold/specs/IDigitalax.sol new file mode 100644 index 00000000..11470ed5 --- /dev/null +++ b/contracts/manifold/specs/IDigitalax.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Digitalax nfts + */ +interface IDigitalax { + function accessControls() external view returns (address); +} + +/** + * @dev Digitalax Access Controls Simple + */ +interface IDigitalaxAccessControls { + function hasAdminRole(address _account) external view returns (bool); +} diff --git a/contracts/manifold/specs/IEIP2981.sol b/contracts/manifold/specs/IEIP2981.sol new file mode 100644 index 00000000..bbbd3a2a --- /dev/null +++ b/contracts/manifold/specs/IEIP2981.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * EIP-2981 + */ +interface IEIP2981 { + /** + * bytes4(keccak256("royaltyInfo(uint256,uint256)")) == 0x2a55205a + * + * => 0x2a55205a = 0x2a55205a + */ + function royaltyInfo(uint256 tokenId, uint256 value) external view returns (address, uint256); +} diff --git a/contracts/manifold/specs/IFoundation.sol b/contracts/manifold/specs/IFoundation.sol new file mode 100644 index 00000000..36632080 --- /dev/null +++ b/contracts/manifold/specs/IFoundation.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +interface IFoundation { + /* + * bytes4(keccak256('getFees(uint256)')) == 0xd5a06d4c + * + * => 0xd5a06d4c = 0xd5a06d4c + */ + function getFees(uint256 tokenId) external view returns (address payable[] memory, uint256[] memory); +} + +interface IFoundationTreasuryNode { + function getFoundationTreasury() external view returns (address payable); +} + +interface IFoundationTreasury { + function isAdmin(address account) external view returns (bool); +} diff --git a/contracts/manifold/specs/IKODAV2Override.sol b/contracts/manifold/specs/IKODAV2Override.sol new file mode 100644 index 00000000..a9914c57 --- /dev/null +++ b/contracts/manifold/specs/IKODAV2Override.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT + +/// @author: knownorigin.io + +pragma solidity ^0.8.0; + +interface IKODAV2 { + function editionOfTokenId(uint256 _tokenId) external view returns (uint256 _editionNumber); + + function artistCommission(uint256 _editionNumber) external view returns (address _artistAccount, uint256 _artistCommission); + + function editionOptionalCommission(uint256 _editionNumber) external view returns (uint256 _rate, address _recipient); +} + +interface IKODAV2Override { + /// @notice Emitted when the royalties fee changes + event CreatorRoyaltiesFeeUpdated(uint256 _oldCreatorRoyaltiesFee, uint256 _newCreatorRoyaltiesFee); + + /// @notice For the given KO NFT and token ID, return the addresses and the amounts to pay + function getKODAV2RoyaltyInfo( + address _tokenAddress, + uint256 _id, + uint256 _amount + ) external view returns (address payable[] memory, uint256[] memory); + + /// @notice Allows the owner() to update the creator royalties + function updateCreatorRoyalties(uint256 _creatorRoyaltiesFee) external; +} diff --git a/contracts/manifold/specs/IManifold.sol b/contracts/manifold/specs/IManifold.sol new file mode 100644 index 00000000..b4ef19ea --- /dev/null +++ b/contracts/manifold/specs/IManifold.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/// @author: manifold.xyz + +/** + * @dev Royalty interface for creator core classes + */ +interface IManifold { + /** + * @dev Get royalites of a token. Returns list of receivers and basisPoints + * + * bytes4(keccak256('getRoyalties(uint256)')) == 0xbb3bafd6 + * + * => 0xbb3bafd6 = 0xbb3bafd6 + */ + function getRoyalties(uint256 tokenId) external view returns (address payable[] memory, uint256[] memory); +} diff --git a/contracts/manifold/specs/INiftyGateway.sol b/contracts/manifold/specs/INiftyGateway.sol new file mode 100644 index 00000000..eff21749 --- /dev/null +++ b/contracts/manifold/specs/INiftyGateway.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Nifty builder instance + */ +interface INiftyBuilderInstance { + function niftyRegistryContract() external view returns (address); +} + +/** + * @dev Nifty registry + */ +interface INiftyRegistry { + /** + * @dev function to see if sending key is valid + */ + function isValidNiftySender(address sending_key) external view returns (bool); +} diff --git a/contracts/manifold/specs/IRarible.sol b/contracts/manifold/specs/IRarible.sol new file mode 100644 index 00000000..7f7fb2c0 --- /dev/null +++ b/contracts/manifold/specs/IRarible.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +interface IRaribleV1 { + /* + * bytes4(keccak256('getFeeBps(uint256)')) == 0x0ebd4c7f + * bytes4(keccak256('getFeeRecipients(uint256)')) == 0xb9c4d9fb + * + * => 0x0ebd4c7f ^ 0xb9c4d9fb == 0xb7799584 + */ + function getFeeBps(uint256 id) external view returns (uint256[] memory); + + function getFeeRecipients(uint256 id) external view returns (address payable[] memory); +} + +interface IRaribleV2 { + /* + * bytes4(keccak256('getRaribleV2Royalties(uint256)')) == 0xcad96cca + */ + struct Part { + address payable account; + uint96 value; + } + + function getRaribleV2Royalties(uint256 id) external view returns (Part[] memory); +} diff --git a/contracts/manifold/specs/ISuperRare.sol b/contracts/manifold/specs/ISuperRare.sol new file mode 100644 index 00000000..e3b50b68 --- /dev/null +++ b/contracts/manifold/specs/ISuperRare.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +interface ISuperRareRegistry { + /** + * @dev Get the royalty fee percentage for a specific ERC721 contract. + * @param _contractAddress address ERC721Contract address. + * @param _tokenId uint256 token ID. + * @return uint8 wei royalty fee. + */ + function getERC721TokenRoyaltyPercentage(address _contractAddress, uint256 _tokenId) external view returns (uint8); + + /** + * @dev Utililty function to calculate the royalty fee for a token. + * @param _contractAddress address ERC721Contract address. + * @param _tokenId uint256 token ID. + * @param _amount uint256 wei amount. + * @return uint256 wei fee. + */ + function calculateRoyaltyFee( + address _contractAddress, + uint256 _tokenId, + uint256 _amount + ) external view returns (uint256); + + /** + * @dev Get the token creator which will receive royalties of the given token + * @param _contractAddress address ERC721Contract address. + * @param _tokenId uint256 token ID. + */ + function tokenCreator(address _contractAddress, uint256 _tokenId) external view returns (address payable); +} diff --git a/contracts/manifold/specs/IZoraOverride.sol b/contracts/manifold/specs/IZoraOverride.sol new file mode 100644 index 00000000..e2860175 --- /dev/null +++ b/contracts/manifold/specs/IZoraOverride.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * Paired down version of the Zora Market interface + */ +interface IZoraMarket { + struct ZoraDecimal { + uint256 value; + } + + struct ZoraBidShares { + // % of sale value that goes to the _previous_ owner of the nft + ZoraDecimal prevOwner; + // % of sale value that goes to the original creator of the nft + ZoraDecimal creator; + // % of sale value that goes to the seller (current owner) of the nft + ZoraDecimal owner; + } + + function bidSharesForToken(uint256 tokenId) external view returns (ZoraBidShares memory); +} + +/** + * Paired down version of the Zora Media interface + */ +interface IZoraMedia { + /** + * Auto-generated accessors of public variables + */ + function marketContract() external view returns (address); + + function previousTokenOwners(uint256 tokenId) external view returns (address); + + function tokenCreators(uint256 tokenId) external view returns (address); + + /** + * ERC721 function + */ + function ownerOf(uint256 tokenId) external view returns (address owner); +} + +/** + * Interface for a Zora media override + */ +interface IZoraOverride { + /** + * @dev Convert bid share configuration of a Zora Media token into an array of receivers and bps values + * Does not support prevOwner and sell-on amounts as that is specific to Zora marketplace implementation + * and requires updates on the Zora Media and Marketplace to update the sell-on amounts/previous owner values. + * An off-Zora marketplace sale will break the sell-on functionality. + */ + function convertBidShares(address media, uint256 tokenId) external view returns (address payable[] memory, uint256[] memory); +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..b4c1a4b7 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6856 @@ +{ + "name": "@zoralabs/v3", + "version": "1.0.14", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@zoralabs/v3", + "version": "1.0.14", + "dependencies": { + "@manifoldxyz/royalty-registry-solidity": "^1.0.9", + "@openzeppelin/contracts": "^4.5.0", + "@rari-capital/solmate": "^6.2.0" + }, + "devDependencies": { + "@typechain/ethers-v5": "^10.0.0", + "husky": "^7.0.0", + "lint-staged": "^12.3.7", + "prettier": "^2.6.1", + "prettier-plugin-solidity": "^1.0.0-beta.19", + "solhint": "^3.3.7", + "solhint-plugin-prettier": "^0.0.5", + "typechain": "^8.0.0", + "typescript": "^4.6.3" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "node_modules/@ethersproject/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "node_modules/@ethersproject/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true + }, + "node_modules/@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "node_modules/@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "node_modules/@ethersproject/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/json-wallets": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@manifoldxyz/libraries-solidity": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@manifoldxyz/libraries-solidity/-/libraries-solidity-1.0.2.tgz", + "integrity": "sha512-qdCLBD5CicgT6UtDB1fED1kpJfgDqIB6WahtsfZ23ha/nYEBXKHJZ1urIHaIeCOdw8cTi6fMQbQWrld4V1S7dQ==", + "deprecated": "this package has been deprecated", + "dependencies": { + "@openzeppelin/contracts": "^4.2.0", + "@openzeppelin/contracts-upgradeable": "^4.2.0" + } + }, + "node_modules/@manifoldxyz/royalty-registry-solidity": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@manifoldxyz/royalty-registry-solidity/-/royalty-registry-solidity-1.0.9.tgz", + "integrity": "sha512-Cv38ROezkl6J8lizyPlEmPoAvLiRcO31OnWe/Jept0mNk7oygrPZrfG07OMfwphn+dOFxmszQTns7AJRQfxMBA==", + "deprecated": "this package has been deprecated", + "dependencies": { + "@manifoldxyz/libraries-solidity": "^1.0.2", + "@openzeppelin/contracts": "^4.3.2", + "@openzeppelin/contracts-upgradeable": "^4.3.2" + } + }, + "node_modules/@openzeppelin/contracts": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.6.0.tgz", + "integrity": "sha512-8vi4d50NNya/bQqCmaVzvHNmwHvS0OBKb7HNtuNwEE3scXWrP31fKQoGxNMT+KbzmrNZzatE3QK5p2gFONI/hg==" + }, + "node_modules/@openzeppelin/contracts-upgradeable": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.4.2.tgz", + "integrity": "sha512-bavxs18L47EmcdnL9I6DzsVSUJO+0/zD6zH7/6qG7QRBugvR3VNVZR+nMvuZlCNwuTTnCa3apR00PYzYr/efAw==" + }, + "node_modules/@rari-capital/solmate": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@rari-capital/solmate/-/solmate-6.2.0.tgz", + "integrity": "sha512-g94F+Ra9ixyJyNgvnOIufNjUz488uEG0nxIEEtJ7+g+tA1XGUupRB2kB5b+VO7WYO26RNOVD2fW6xE4e14iWpg==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info." + }, + "node_modules/@solidity-parser/parser": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.2.tgz", + "integrity": "sha512-10cr0s+MtRtqjEw0WFJrm2rwULN30xx7btd/v9cmqME2617/2M5MbHDkFIGIGTa7lwNw4bN9mVGfhlLzrYw8pA==", + "dev": true, + "dependencies": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "node_modules/@typechain/ethers-v5": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@typechain/ethers-v5/-/ethers-v5-10.1.0.tgz", + "integrity": "sha512-3LIb+eUpV3mNCrjUKT5oqp8PBsZYSnVrkfk6pY/ZM0boRs2mKxjFZ7bktx42vfDye8PPz3NxtW4DL5NsNsFqlg==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15", + "ts-essentials": "^7.0.1" + }, + "peerDependencies": { + "@ethersproject/abi": "^5.0.0", + "@ethersproject/bytes": "^5.0.0", + "@ethersproject/providers": "^5.0.0", + "ethers": "^5.1.3", + "typechain": "^8.1.0", + "typescript": ">=4.3.0" + } + }, + "node_modules/@types/prettier": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.3.tgz", + "integrity": "sha512-QzSuZMBuG5u8HqYz01qtMdg/Jfctlnvj1z/lYnIDXs/golxw0fxtRAHd9KrzjR7Yxz1qVeI00o0kiO3PmVdJ9w==", + "dev": true + }, + "node_modules/acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true, + "peer": true + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= sha512-wFUFA5bg5dviipbQQ32yOQhl6gcJaJXiHE7dvR8VYPG97+J/GNC5FKGepKdEDUFeXRzDxPF1X/Btc8L+v7oqIQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-styles": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.0.tgz", + "integrity": "sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/antlr4": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.7.1.tgz", + "integrity": "sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ==", + "dev": true + }, + "node_modules/antlr4ts": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ast-parents": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/ast-parents/-/ast-parents-0.0.1.tgz", + "integrity": "sha1-UI/Q8F0MSHddnszaLhdEIyYejdM= sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==", + "dev": true + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "dev": true, + "peer": true + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true, + "peer": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true, + "peer": true + }, + "node_modules/caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", + "dev": true, + "dependencies": { + "callsites": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", + "dev": true, + "dependencies": { + "caller-callsite": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "dev": true + }, + "node_modules/command-line-args": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.0.tgz", + "integrity": "sha512-4zqtU1hYsSJzcJBOcNZIbW5Fbk9BkjCp1pZVhQKoRaWL5J7N4XphDLwo8aWwdQpTugxwu+jf9u2ZhkXiqp5Z6A==", + "dev": true, + "dependencies": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-usage": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.1.tgz", + "integrity": "sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA==", + "dev": true, + "dependencies": { + "array-back": "^4.0.1", + "chalk": "^2.4.2", + "table-layout": "^1.0.1", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/command-line-usage/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/command-line-usage/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/commander": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz", + "integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "dependencies": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "peer": true, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true, + "peer": true + }, + "node_modules/emoji-regex": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.0.0.tgz", + "integrity": "sha512-KmJa8l6uHi1HrBI34udwlzZY1jOEuID/ft4d8BSSEdRyap7PwBEt910453PJa5MuGvxkLqlt4Uvhu7tttFHViw==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", + "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.9.1", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^4.0.3", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^5.0.1", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.2.2", + "js-yaml": "^3.13.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^5.5.1", + "strip-ansi": "^4.0.0", + "strip-json-comments": "^2.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^6.14.0 || ^8.10.0 || >=9.10.0" + } + }, + "node_modules/eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/eslint/node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/eslint/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/espree": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", + "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", + "dev": true, + "dependencies": { + "acorn": "^6.0.7", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ethers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "dependencies": { + "flat-cache": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "dev": true, + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "dependencies": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8= sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "dev": true + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0= sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "peer": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/husky": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", + "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "dev": true, + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY= sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", + "dev": true, + "dependencies": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o= sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/inquirer": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/inquirer/node_modules/ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/inquirer/node_modules/cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", + "dev": true, + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/inquirer/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/inquirer/node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/inquirer/node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/inquirer/node_modules/restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368= sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", + "dev": true, + "dependencies": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/inquirer/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/inquirer/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/inquirer/node_modules/string-width/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8= sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/inquirer/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/inquirer/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/inquirer/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz", + "integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/lint-staged": { + "version": "12.5.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-12.5.0.tgz", + "integrity": "sha512-BKLUjWDsKquV/JuIcoQW4MSAI3ggwEImF1+sB4zaKvyVx1wBk3FsG7UK9bpnmBTN1pm7EH2BBcMwINJzCRv12g==", + "dev": true, + "dependencies": { + "cli-truncate": "^3.1.0", + "colorette": "^2.0.16", + "commander": "^9.3.0", + "debug": "^4.3.4", + "execa": "^5.1.1", + "lilconfig": "2.0.5", + "listr2": "^4.0.5", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-inspect": "^1.12.2", + "pidtree": "^0.5.0", + "string-argv": "^0.3.1", + "supports-color": "^9.2.2", + "yaml": "^1.10.2" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/listr2": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.5.tgz", + "integrity": "sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==", + "dev": true, + "dependencies": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.5", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } + } + }, + "node_modules/listr2/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/listr2/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/listr2/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/listr2/node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/listr2/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/listr2/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY= sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true + }, + "node_modules/log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-update/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true, + "peer": true + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true, + "peer": true + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E= sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module/node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18= sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "dev": true + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.5.0.tgz", + "integrity": "sha512-9nxspIM7OpZuhBxPg73Zvyq7j1QMPMPsGKTqRc2XOaFQauDvoNz9fM1Wdkjmeo7l9GXOZiRs97sPkuayl39wjA==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/prettier-plugin-solidity": { + "version": "1.0.0-beta.19", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.19.tgz", + "integrity": "sha512-xxRQ5ZiiZyUoMFLE9h7HnUDXI/daf1tnmL1msEdcKmyh7ZGQ4YklkYLC71bfBpYU2WruTb5/SFLUaEb3RApg5g==", + "dev": true, + "dependencies": { + "@solidity-parser/parser": "^0.14.0", + "emoji-regex": "^10.0.0", + "escape-string-regexp": "^4.0.0", + "semver": "^7.3.5", + "solidity-comments-extractor": "^0.0.7", + "string-width": "^4.2.3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "prettier": "^2.3.0" + } + }, + "node_modules/prettier-plugin-solidity/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/prettier-plugin-solidity/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/prettier-plugin-solidity/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prettier-plugin-solidity/node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/prettier-plugin-solidity/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true, + "engines": { + "node": ">=6.5.0" + } + }, + "node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g= sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/rxjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true, + "peer": true + }, + "node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", + "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==", + "dev": true + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/solhint": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.3.7.tgz", + "integrity": "sha512-NjjjVmXI3ehKkb3aNtRJWw55SUVJ8HMKKodwe0HnejA+k0d2kmhw7jvpa+MCTbcEgt8IWSwx0Hu6aCo/iYOZzQ==", + "dev": true, + "dependencies": { + "@solidity-parser/parser": "^0.14.1", + "ajv": "^6.6.1", + "antlr4": "4.7.1", + "ast-parents": "0.0.1", + "chalk": "^2.4.2", + "commander": "2.18.0", + "cosmiconfig": "^5.0.7", + "eslint": "^5.6.0", + "fast-diff": "^1.1.2", + "glob": "^7.1.3", + "ignore": "^4.0.6", + "js-yaml": "^3.12.0", + "lodash": "^4.17.11", + "semver": "^6.3.0" + }, + "bin": { + "solhint": "solhint.js" + }, + "optionalDependencies": { + "prettier": "^1.14.3" + } + }, + "node_modules/solhint-plugin-prettier": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/solhint-plugin-prettier/-/solhint-plugin-prettier-0.0.5.tgz", + "integrity": "sha512-7jmWcnVshIrO2FFinIvDQmhQpfpS2rRRn3RejiYgnjIE68xO2bvrYvjqVNfrio4xH9ghOqn83tKuTzLjEbmGIA==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "peerDependencies": { + "prettier": "^1.15.0 || ^2.0.0", + "prettier-plugin-solidity": "^1.0.0-alpha.14" + } + }, + "node_modules/solhint/node_modules/commander": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.18.0.tgz", + "integrity": "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==", + "dev": true + }, + "node_modules/solhint/node_modules/prettier": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "dev": true, + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/solhint/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/solidity-comments-extractor": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz", + "integrity": "sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/string-argv": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", + "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "dev": true, + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-format": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-format/-/string-format-2.0.0.tgz", + "integrity": "sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==", + "dev": true + }, + "node_modules/string-width": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.0.tgz", + "integrity": "sha512-7x54QnN21P+XL/v8SuNKvfgsUre6PXpN7mc77N3HlZv+f1SBRGmjxtOud2Z6FZ8DmdkD/IdjCaf9XXbnqmTZGQ==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8= sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo= sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.2.2.tgz", + "integrity": "sha512-XC6g/Kgux+rJXmwokjm9ECpD6k/smUoS5LKlUCcsYr4IY3rW0XyAympon2RmxGrlnZURMpg5T18gWDP9CsHXFA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "dependencies": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "dev": true, + "dependencies": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/table-layout/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/table-layout/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/table/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/table/node_modules/astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/table/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/table/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/table/node_modules/slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/table/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/table/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-command-line-args": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-command-line-args/-/ts-command-line-args-2.2.0.tgz", + "integrity": "sha512-RedEejZyhiEAOgBkIVxB4QC/SRYtl98D7b7epWB9e6E+TmK8KstXBu3WdnhGbMHicLkHoG7sCAmu+F+ASzLFHA==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "command-line-args": "^5.1.1", + "command-line-usage": "^6.1.0", + "string-format": "^2.0.0" + }, + "bin": { + "write-markdown": "dist/write-markdown.js" + } + }, + "node_modules/ts-command-line-args/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ts-command-line-args/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ts-command-line-args/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ts-command-line-args/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/ts-command-line-args/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-command-line-args/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-essentials": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz", + "integrity": "sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==", + "dev": true, + "peerDependencies": { + "typescript": ">=3.7.0" + } + }, + "node_modules/tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typechain": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/typechain/-/typechain-8.1.0.tgz", + "integrity": "sha512-5jToLgKTjHdI1VKqs/K8BLYy42Sr3o8bV5ojh4MnR9ExHO83cyyUdw+7+vMJCpKXUiVUvARM4qmHTFuyaCMAZQ==", + "dev": true, + "dependencies": { + "@types/prettier": "^2.1.1", + "debug": "^4.3.1", + "fs-extra": "^7.0.0", + "glob": "7.1.7", + "js-sha3": "^0.8.0", + "lodash": "^4.17.15", + "mkdirp": "^1.0.4", + "prettier": "^2.3.1", + "ts-command-line-args": "^2.2.0", + "ts-essentials": "^7.0.1" + }, + "bin": { + "typechain": "dist/cli/cli.js" + }, + "peerDependencies": { + "typescript": ">=4.3.0" + } + }, + "node_modules/typechain/node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typechain/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "dev": true, + "dependencies": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/wordwrapjs/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "dependencies": { + "mkdirp": "^0.5.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "@ethersproject/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "@ethersproject/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "dev": true, + "peer": true + }, + "@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "@ethersproject/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "@ethersproject/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/json-wallets": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@manifoldxyz/libraries-solidity": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@manifoldxyz/libraries-solidity/-/libraries-solidity-1.0.2.tgz", + "integrity": "sha512-qdCLBD5CicgT6UtDB1fED1kpJfgDqIB6WahtsfZ23ha/nYEBXKHJZ1urIHaIeCOdw8cTi6fMQbQWrld4V1S7dQ==", + "requires": { + "@openzeppelin/contracts": "^4.2.0", + "@openzeppelin/contracts-upgradeable": "^4.2.0" + } + }, + "@manifoldxyz/royalty-registry-solidity": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@manifoldxyz/royalty-registry-solidity/-/royalty-registry-solidity-1.0.9.tgz", + "integrity": "sha512-Cv38ROezkl6J8lizyPlEmPoAvLiRcO31OnWe/Jept0mNk7oygrPZrfG07OMfwphn+dOFxmszQTns7AJRQfxMBA==", + "requires": { + "@manifoldxyz/libraries-solidity": "^1.0.2", + "@openzeppelin/contracts": "^4.3.2", + "@openzeppelin/contracts-upgradeable": "^4.3.2" + } + }, + "@openzeppelin/contracts": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.6.0.tgz", + "integrity": "sha512-8vi4d50NNya/bQqCmaVzvHNmwHvS0OBKb7HNtuNwEE3scXWrP31fKQoGxNMT+KbzmrNZzatE3QK5p2gFONI/hg==" + }, + "@openzeppelin/contracts-upgradeable": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.4.2.tgz", + "integrity": "sha512-bavxs18L47EmcdnL9I6DzsVSUJO+0/zD6zH7/6qG7QRBugvR3VNVZR+nMvuZlCNwuTTnCa3apR00PYzYr/efAw==" + }, + "@rari-capital/solmate": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@rari-capital/solmate/-/solmate-6.2.0.tgz", + "integrity": "sha512-g94F+Ra9ixyJyNgvnOIufNjUz488uEG0nxIEEtJ7+g+tA1XGUupRB2kB5b+VO7WYO26RNOVD2fW6xE4e14iWpg==" + }, + "@solidity-parser/parser": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.2.tgz", + "integrity": "sha512-10cr0s+MtRtqjEw0WFJrm2rwULN30xx7btd/v9cmqME2617/2M5MbHDkFIGIGTa7lwNw4bN9mVGfhlLzrYw8pA==", + "dev": true, + "requires": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "@typechain/ethers-v5": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@typechain/ethers-v5/-/ethers-v5-10.1.0.tgz", + "integrity": "sha512-3LIb+eUpV3mNCrjUKT5oqp8PBsZYSnVrkfk6pY/ZM0boRs2mKxjFZ7bktx42vfDye8PPz3NxtW4DL5NsNsFqlg==", + "dev": true, + "requires": { + "lodash": "^4.17.15", + "ts-essentials": "^7.0.1" + } + }, + "@types/prettier": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.3.tgz", + "integrity": "sha512-QzSuZMBuG5u8HqYz01qtMdg/Jfctlnvj1z/lYnIDXs/golxw0fxtRAHd9KrzjR7Yxz1qVeI00o0kiO3PmVdJ9w==", + "dev": true + }, + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true, + "peer": true + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= sha512-wFUFA5bg5dviipbQQ32yOQhl6gcJaJXiHE7dvR8VYPG97+J/GNC5FKGepKdEDUFeXRzDxPF1X/Btc8L+v7oqIQ==", + "dev": true + }, + "ansi-styles": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.0.tgz", + "integrity": "sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==", + "dev": true + }, + "antlr4": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.7.1.tgz", + "integrity": "sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ==", + "dev": true + }, + "antlr4ts": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true + }, + "ast-parents": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/ast-parents/-/ast-parents-0.0.1.tgz", + "integrity": "sha1-UI/Q8F0MSHddnszaLhdEIyYejdM= sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==", + "dev": true + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "dev": true, + "peer": true + }, + "bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true, + "peer": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true, + "peer": true + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", + "dev": true, + "requires": { + "callsites": "^2.0.0" + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, + "requires": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + } + }, + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "colorette": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "dev": true + }, + "command-line-args": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.0.tgz", + "integrity": "sha512-4zqtU1hYsSJzcJBOcNZIbW5Fbk9BkjCp1pZVhQKoRaWL5J7N4XphDLwo8aWwdQpTugxwu+jf9u2ZhkXiqp5Z6A==", + "dev": true, + "requires": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + } + }, + "command-line-usage": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.1.tgz", + "integrity": "sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA==", + "dev": true, + "requires": { + "array-back": "^4.0.1", + "chalk": "^2.4.2", + "table-layout": "^1.0.1", + "typical": "^5.2.0" + }, + "dependencies": { + "array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true + }, + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true + } + } + }, + "commander": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz", + "integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "peer": true, + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true, + "peer": true + } + } + }, + "emoji-regex": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.0.0.tgz", + "integrity": "sha512-KmJa8l6uHi1HrBI34udwlzZY1jOEuID/ft4d8BSSEdRyap7PwBEt910453PJa5MuGvxkLqlt4Uvhu7tttFHViw==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", + "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.9.1", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^4.0.3", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^5.0.1", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.2.2", + "js-yaml": "^3.13.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^5.5.1", + "strip-ansi": "^4.0.0", + "strip-json-comments": "^2.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", + "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", + "dev": true, + "requires": { + "acorn": "^6.0.7", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "ethers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" + } + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + } + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "dev": true, + "requires": { + "array-back": "^3.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8= sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0= sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "peer": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "peer": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "husky": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", + "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY= sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o= sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "inquirer": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368= sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8= sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "lilconfig": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz", + "integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==", + "dev": true + }, + "lint-staged": { + "version": "12.5.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-12.5.0.tgz", + "integrity": "sha512-BKLUjWDsKquV/JuIcoQW4MSAI3ggwEImF1+sB4zaKvyVx1wBk3FsG7UK9bpnmBTN1pm7EH2BBcMwINJzCRv12g==", + "dev": true, + "requires": { + "cli-truncate": "^3.1.0", + "colorette": "^2.0.16", + "commander": "^9.3.0", + "debug": "^4.3.4", + "execa": "^5.1.1", + "lilconfig": "2.0.5", + "listr2": "^4.0.5", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-inspect": "^1.12.2", + "pidtree": "^0.5.0", + "string-argv": "^0.3.1", + "supports-color": "^9.2.2", + "yaml": "^1.10.2" + } + }, + "listr2": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.5.tgz", + "integrity": "sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==", + "dev": true, + "requires": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.5", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "requires": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY= sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true + }, + "log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true, + "peer": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true, + "peer": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E= sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + }, + "dependencies": { + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + } + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18= sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pidtree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.5.0.tgz", + "integrity": "sha512-9nxspIM7OpZuhBxPg73Zvyq7j1QMPMPsGKTqRc2XOaFQauDvoNz9fM1Wdkjmeo7l9GXOZiRs97sPkuayl39wjA==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true + }, + "prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "prettier-plugin-solidity": { + "version": "1.0.0-beta.19", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.19.tgz", + "integrity": "sha512-xxRQ5ZiiZyUoMFLE9h7HnUDXI/daf1tnmL1msEdcKmyh7ZGQ4YklkYLC71bfBpYU2WruTb5/SFLUaEb3RApg5g==", + "dev": true, + "requires": { + "@solidity-parser/parser": "^0.14.0", + "emoji-regex": "^10.0.0", + "escape-string-regexp": "^4.0.0", + "semver": "^7.3.5", + "solidity-comments-extractor": "^0.0.7", + "string-width": "^4.2.3" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + } + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "dev": true + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g= sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", + "dev": true + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "rxjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true, + "peer": true + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "signal-exit": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", + "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==", + "dev": true + }, + "slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + } + }, + "solhint": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.3.7.tgz", + "integrity": "sha512-NjjjVmXI3ehKkb3aNtRJWw55SUVJ8HMKKodwe0HnejA+k0d2kmhw7jvpa+MCTbcEgt8IWSwx0Hu6aCo/iYOZzQ==", + "dev": true, + "requires": { + "@solidity-parser/parser": "^0.14.1", + "ajv": "^6.6.1", + "antlr4": "4.7.1", + "ast-parents": "0.0.1", + "chalk": "^2.4.2", + "commander": "2.18.0", + "cosmiconfig": "^5.0.7", + "eslint": "^5.6.0", + "fast-diff": "^1.1.2", + "glob": "^7.1.3", + "ignore": "^4.0.6", + "js-yaml": "^3.12.0", + "lodash": "^4.17.11", + "prettier": "^1.14.3", + "semver": "^6.3.0" + }, + "dependencies": { + "commander": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.18.0.tgz", + "integrity": "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==", + "dev": true + }, + "prettier": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "dev": true, + "optional": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "solhint-plugin-prettier": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/solhint-plugin-prettier/-/solhint-plugin-prettier-0.0.5.tgz", + "integrity": "sha512-7jmWcnVshIrO2FFinIvDQmhQpfpS2rRRn3RejiYgnjIE68xO2bvrYvjqVNfrio4xH9ghOqn83tKuTzLjEbmGIA==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "solidity-comments-extractor": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz", + "integrity": "sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "string-argv": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", + "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "dev": true + }, + "string-format": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-format/-/string-format-2.0.0.tgz", + "integrity": "sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==", + "dev": true + }, + "string-width": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.0.tgz", + "integrity": "sha512-7x54QnN21P+XL/v8SuNKvfgsUre6PXpN7mc77N3HlZv+f1SBRGmjxtOud2Z6FZ8DmdkD/IdjCaf9XXbnqmTZGQ==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8= sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo= sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true + }, + "supports-color": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.2.2.tgz", + "integrity": "sha512-XC6g/Kgux+rJXmwokjm9ECpD6k/smUoS5LKlUCcsYr4IY3rW0XyAympon2RmxGrlnZURMpg5T18gWDP9CsHXFA==", + "dev": true + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "dev": true, + "requires": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "dependencies": { + "array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true + }, + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "ts-command-line-args": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-command-line-args/-/ts-command-line-args-2.2.0.tgz", + "integrity": "sha512-RedEejZyhiEAOgBkIVxB4QC/SRYtl98D7b7epWB9e6E+TmK8KstXBu3WdnhGbMHicLkHoG7sCAmu+F+ASzLFHA==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "command-line-args": "^5.1.1", + "command-line-usage": "^6.1.0", + "string-format": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "ts-essentials": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz", + "integrity": "sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==", + "dev": true, + "requires": {} + }, + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + }, + "typechain": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/typechain/-/typechain-8.1.0.tgz", + "integrity": "sha512-5jToLgKTjHdI1VKqs/K8BLYy42Sr3o8bV5ojh4MnR9ExHO83cyyUdw+7+vMJCpKXUiVUvARM4qmHTFuyaCMAZQ==", + "dev": true, + "requires": { + "@types/prettier": "^2.1.1", + "debug": "^4.3.1", + "fs-extra": "^7.0.0", + "glob": "7.1.7", + "js-sha3": "^0.8.0", + "lodash": "^4.17.15", + "mkdirp": "^1.0.4", + "prettier": "^2.3.1", + "ts-command-line-args": "^2.2.0", + "ts-essentials": "^7.0.1" + }, + "dependencies": { + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + } + } + }, + "typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true + }, + "typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "dev": true + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "dev": true, + "requires": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "dependencies": { + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true + } + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "dev": true, + "peer": true, + "requires": {} + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + } + } +} diff --git a/yarn.lock b/yarn.lock index 78af3032..bc083d3e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3,1676 +3,2147 @@ "@babel/code-frame@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" - integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + "integrity" "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==" + "resolved" "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz" + "version" "7.16.7" dependencies: "@babel/highlight" "^7.16.7" "@babel/helper-validator-identifier@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" - integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + "integrity" "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==" + "resolved" "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz" + "version" "7.16.7" "@babel/highlight@^7.16.7": - version "7.16.10" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" - integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== + "integrity" "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==" + "resolved" "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz" + "version" "7.16.10" dependencies: "@babel/helper-validator-identifier" "^7.16.7" - chalk "^2.0.0" - js-tokens "^4.0.0" + "chalk" "^2.0.0" + "js-tokens" "^4.0.0" + +"@ethersproject/abi@^5.0.0", "@ethersproject/abi@^5.7.0", "@ethersproject/abi@5.7.0": + "integrity" "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==" + "resolved" "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/abstract-provider@^5.7.0", "@ethersproject/abstract-provider@5.7.0": + "integrity" "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==" + "resolved" "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + +"@ethersproject/abstract-signer@^5.7.0", "@ethersproject/abstract-signer@5.7.0": + "integrity" "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==" + "resolved" "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/address@^5.7.0", "@ethersproject/address@5.7.0": + "integrity" "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==" + "resolved" "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + +"@ethersproject/base64@^5.7.0", "@ethersproject/base64@5.7.0": + "integrity" "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==" + "resolved" "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/bytes" "^5.7.0" + +"@ethersproject/basex@^5.7.0", "@ethersproject/basex@5.7.0": + "integrity" "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==" + "resolved" "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/bignumber@^5.7.0", "@ethersproject/bignumber@5.7.0": + "integrity" "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==" + "resolved" "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "bn.js" "^5.2.1" + +"@ethersproject/bytes@^5.0.0", "@ethersproject/bytes@^5.7.0", "@ethersproject/bytes@5.7.0": + "integrity" "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==" + "resolved" "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/constants@^5.7.0", "@ethersproject/constants@5.7.0": + "integrity" "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==" + "resolved" "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/bignumber" "^5.7.0" + +"@ethersproject/contracts@5.7.0": + "integrity" "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==" + "resolved" "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + +"@ethersproject/hash@^5.7.0", "@ethersproject/hash@5.7.0": + "integrity" "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==" + "resolved" "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/hdnode@^5.7.0", "@ethersproject/hdnode@5.7.0": + "integrity" "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==" + "resolved" "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/json-wallets@^5.7.0", "@ethersproject/json-wallets@5.7.0": + "integrity" "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==" + "resolved" "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "aes-js" "3.0.0" + "scrypt-js" "3.0.1" + +"@ethersproject/keccak256@^5.7.0", "@ethersproject/keccak256@5.7.0": + "integrity" "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==" + "resolved" "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/bytes" "^5.7.0" + "js-sha3" "0.8.0" + +"@ethersproject/logger@^5.7.0", "@ethersproject/logger@5.7.0": + "integrity" "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==" + "resolved" "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz" + "version" "5.7.0" + +"@ethersproject/networks@^5.7.0", "@ethersproject/networks@5.7.1": + "integrity" "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==" + "resolved" "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz" + "version" "5.7.1" + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/pbkdf2@^5.7.0", "@ethersproject/pbkdf2@5.7.0": + "integrity" "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==" + "resolved" "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + +"@ethersproject/properties@^5.7.0", "@ethersproject/properties@5.7.0": + "integrity" "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==" + "resolved" "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/providers@^5.0.0", "@ethersproject/providers@5.7.2": + "integrity" "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==" + "resolved" "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz" + "version" "5.7.2" + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + "bech32" "1.1.4" + "ws" "7.4.6" + +"@ethersproject/random@^5.7.0", "@ethersproject/random@5.7.0": + "integrity" "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==" + "resolved" "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/rlp@^5.7.0", "@ethersproject/rlp@5.7.0": + "integrity" "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==" + "resolved" "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/sha2@^5.7.0", "@ethersproject/sha2@5.7.0": + "integrity" "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==" + "resolved" "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "hash.js" "1.1.7" + +"@ethersproject/signing-key@^5.7.0", "@ethersproject/signing-key@5.7.0": + "integrity" "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==" + "resolved" "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "bn.js" "^5.2.1" + "elliptic" "6.5.4" + "hash.js" "1.1.7" + +"@ethersproject/solidity@5.7.0": + "integrity" "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==" + "resolved" "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/strings@^5.7.0", "@ethersproject/strings@5.7.0": + "integrity" "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==" + "resolved" "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/transactions@^5.7.0", "@ethersproject/transactions@5.7.0": + "integrity" "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==" + "resolved" "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + +"@ethersproject/units@5.7.0": + "integrity" "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==" + "resolved" "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/wallet@5.7.0": + "integrity" "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==" + "resolved" "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/json-wallets" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/web@^5.7.0", "@ethersproject/web@5.7.1": + "integrity" "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==" + "resolved" "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz" + "version" "5.7.1" + dependencies: + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/wordlists@^5.7.0", "@ethersproject/wordlists@5.7.0": + "integrity" "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==" + "resolved" "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz" + "version" "5.7.0" + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" "@manifoldxyz/libraries-solidity@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@manifoldxyz/libraries-solidity/-/libraries-solidity-1.0.2.tgz#c63284d910ff6e7af3e1954a54dd126abd084518" - integrity sha512-qdCLBD5CicgT6UtDB1fED1kpJfgDqIB6WahtsfZ23ha/nYEBXKHJZ1urIHaIeCOdw8cTi6fMQbQWrld4V1S7dQ== + "integrity" "sha512-qdCLBD5CicgT6UtDB1fED1kpJfgDqIB6WahtsfZ23ha/nYEBXKHJZ1urIHaIeCOdw8cTi6fMQbQWrld4V1S7dQ==" + "resolved" "https://registry.npmjs.org/@manifoldxyz/libraries-solidity/-/libraries-solidity-1.0.2.tgz" + "version" "1.0.2" dependencies: "@openzeppelin/contracts" "^4.2.0" "@openzeppelin/contracts-upgradeable" "^4.2.0" "@manifoldxyz/royalty-registry-solidity@^1.0.9": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@manifoldxyz/royalty-registry-solidity/-/royalty-registry-solidity-1.0.9.tgz#4d3516338c8b351e1e61d5a597ec532574beed6d" - integrity sha512-Cv38ROezkl6J8lizyPlEmPoAvLiRcO31OnWe/Jept0mNk7oygrPZrfG07OMfwphn+dOFxmszQTns7AJRQfxMBA== + "integrity" "sha512-Cv38ROezkl6J8lizyPlEmPoAvLiRcO31OnWe/Jept0mNk7oygrPZrfG07OMfwphn+dOFxmszQTns7AJRQfxMBA==" + "resolved" "https://registry.npmjs.org/@manifoldxyz/royalty-registry-solidity/-/royalty-registry-solidity-1.0.9.tgz" + "version" "1.0.9" dependencies: "@manifoldxyz/libraries-solidity" "^1.0.2" "@openzeppelin/contracts" "^4.3.2" "@openzeppelin/contracts-upgradeable" "^4.3.2" "@openzeppelin/contracts-upgradeable@^4.2.0", "@openzeppelin/contracts-upgradeable@^4.3.2": - version "4.4.2" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.4.2.tgz#748a5986a02548ef541cabc2ce8c67a890044c40" - integrity sha512-bavxs18L47EmcdnL9I6DzsVSUJO+0/zD6zH7/6qG7QRBugvR3VNVZR+nMvuZlCNwuTTnCa3apR00PYzYr/efAw== + "integrity" "sha512-bavxs18L47EmcdnL9I6DzsVSUJO+0/zD6zH7/6qG7QRBugvR3VNVZR+nMvuZlCNwuTTnCa3apR00PYzYr/efAw==" + "resolved" "https://registry.npmjs.org/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.4.2.tgz" + "version" "4.4.2" -"@openzeppelin/contracts@^4.2.0", "@openzeppelin/contracts@^4.3.2": - version "4.4.2" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.4.2.tgz#4e889c9c66e736f7de189a53f8ba5b8d789425c2" - integrity sha512-NyJV7sJgoGYqbtNUWgzzOGW4T6rR19FmX1IJgXGdapGPWsuMelGJn9h03nos0iqfforCbCB0iYIR0MtIuIFLLw== - -"@openzeppelin/contracts@^4.5.0": - version "4.6.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.6.0.tgz#c91cf64bc27f573836dba4122758b4743418c1b3" - integrity sha512-8vi4d50NNya/bQqCmaVzvHNmwHvS0OBKb7HNtuNwEE3scXWrP31fKQoGxNMT+KbzmrNZzatE3QK5p2gFONI/hg== +"@openzeppelin/contracts@^4.2.0", "@openzeppelin/contracts@^4.3.2", "@openzeppelin/contracts@^4.5.0": + "integrity" "sha512-8vi4d50NNya/bQqCmaVzvHNmwHvS0OBKb7HNtuNwEE3scXWrP31fKQoGxNMT+KbzmrNZzatE3QK5p2gFONI/hg==" + "resolved" "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.6.0.tgz" + "version" "4.6.0" "@rari-capital/solmate@^6.2.0": - version "6.2.0" - resolved "https://registry.yarnpkg.com/@rari-capital/solmate/-/solmate-6.2.0.tgz#4f70dc236606c27ec2cb1b4261dd830235d01fe4" - integrity sha512-g94F+Ra9ixyJyNgvnOIufNjUz488uEG0nxIEEtJ7+g+tA1XGUupRB2kB5b+VO7WYO26RNOVD2fW6xE4e14iWpg== - -"@solidity-parser/parser@^0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.14.0.tgz#d51f074efb0acce0e953ec48133561ed710cebc0" - integrity sha512-cX0JJRcmPtNUJpzD2K7FdA7qQsTOk1UZnFx2k7qAg9ZRvuaH5NBe5IEdBMXGlmf2+FmjhqbygJ26H8l2SV7aKQ== - dependencies: - antlr4ts "^0.5.0-alpha.4" + "integrity" "sha512-g94F+Ra9ixyJyNgvnOIufNjUz488uEG0nxIEEtJ7+g+tA1XGUupRB2kB5b+VO7WYO26RNOVD2fW6xE4e14iWpg==" + "resolved" "https://registry.npmjs.org/@rari-capital/solmate/-/solmate-6.2.0.tgz" + "version" "6.2.0" -"@solidity-parser/parser@^0.14.1": - version "0.14.2" - resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.14.2.tgz#2d8f2bddb217621df882ceeae7d7b42ae8664db3" - integrity sha512-10cr0s+MtRtqjEw0WFJrm2rwULN30xx7btd/v9cmqME2617/2M5MbHDkFIGIGTa7lwNw4bN9mVGfhlLzrYw8pA== +"@solidity-parser/parser@^0.14.0", "@solidity-parser/parser@^0.14.1": + "integrity" "sha512-10cr0s+MtRtqjEw0WFJrm2rwULN30xx7btd/v9cmqME2617/2M5MbHDkFIGIGTa7lwNw4bN9mVGfhlLzrYw8pA==" + "resolved" "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.2.tgz" + "version" "0.14.2" dependencies: - antlr4ts "^0.5.0-alpha.4" + "antlr4ts" "^0.5.0-alpha.4" "@typechain/ethers-v5@^10.0.0": - version "10.1.0" - resolved "https://registry.yarnpkg.com/@typechain/ethers-v5/-/ethers-v5-10.1.0.tgz#068d7dc7014502354696dab59590a7841091e951" - integrity sha512-3LIb+eUpV3mNCrjUKT5oqp8PBsZYSnVrkfk6pY/ZM0boRs2mKxjFZ7bktx42vfDye8PPz3NxtW4DL5NsNsFqlg== + "integrity" "sha512-3LIb+eUpV3mNCrjUKT5oqp8PBsZYSnVrkfk6pY/ZM0boRs2mKxjFZ7bktx42vfDye8PPz3NxtW4DL5NsNsFqlg==" + "resolved" "https://registry.npmjs.org/@typechain/ethers-v5/-/ethers-v5-10.1.0.tgz" + "version" "10.1.0" dependencies: - lodash "^4.17.15" - ts-essentials "^7.0.1" + "lodash" "^4.17.15" + "ts-essentials" "^7.0.1" "@types/prettier@^2.1.1": - version "2.4.3" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.3.tgz#a3c65525b91fca7da00ab1a3ac2b5a2a4afbffbf" - integrity sha512-QzSuZMBuG5u8HqYz01qtMdg/Jfctlnvj1z/lYnIDXs/golxw0fxtRAHd9KrzjR7Yxz1qVeI00o0kiO3PmVdJ9w== - -acorn-jsx@^5.0.0: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn@^6.0.7: - version "6.4.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" - integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== - -aggregate-error@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" - integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - -ajv@^6.10.2, ajv@^6.6.1, ajv@^6.9.1: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-escapes@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== - -ansi-escapes@^4.3.0: - version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-regex@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" - integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.1.0.tgz#87313c102b8118abd57371afab34618bf7350ed3" - integrity sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ== - -antlr4@4.7.1: - version "4.7.1" - resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.7.1.tgz#69984014f096e9e775f53dd9744bf994d8959773" - integrity sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ== - -antlr4ts@^0.5.0-alpha.4: - version "0.5.0-alpha.4" - resolved "https://registry.yarnpkg.com/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz#71702865a87478ed0b40c0709f422cf14d51652a" - integrity sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ== - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -array-back@^3.0.1, array-back@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0" - integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== - -array-back@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/array-back/-/array-back-4.0.2.tgz#8004e999a6274586beeb27342168652fdb89fa1e" - integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg== - -ast-parents@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/ast-parents/-/ast-parents-0.0.1.tgz#508fd0f05d0c48775d9eccda2e174423261e8dd3" - integrity sha1-UI/Q8F0MSHddnszaLhdEIyYejdM= - -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -caller-callsite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" - integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= - dependencies: - callsites "^2.0.0" - -caller-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" - integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= - dependencies: - caller-callsite "^2.0.0" - -callsites@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" - integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - -clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= - dependencies: - restore-cursor "^2.0.0" - -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-truncate@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" - integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== - dependencies: - slice-ansi "^3.0.0" - string-width "^4.2.0" - -cli-truncate@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389" - integrity sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA== - dependencies: - slice-ansi "^5.0.0" - string-width "^5.0.0" - -cli-width@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" - integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -colorette@^2.0.16: - version "2.0.16" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" - integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== - -command-line-args@^5.1.1: - version "5.2.0" - resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.0.tgz#087b02748272169741f1fd7c785b295df079b9be" - integrity sha512-4zqtU1hYsSJzcJBOcNZIbW5Fbk9BkjCp1pZVhQKoRaWL5J7N4XphDLwo8aWwdQpTugxwu+jf9u2ZhkXiqp5Z6A== - dependencies: - array-back "^3.1.0" - find-replace "^3.0.0" - lodash.camelcase "^4.3.0" - typical "^4.0.0" - -command-line-usage@^6.1.0: - version "6.1.1" - resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-6.1.1.tgz#c908e28686108917758a49f45efb4f02f76bc03f" - integrity sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA== - dependencies: - array-back "^4.0.1" - chalk "^2.4.2" - table-layout "^1.0.1" - typical "^5.2.0" - -commander@2.18.0: - version "2.18.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.18.0.tgz#2bf063ddee7c7891176981a2cc798e5754bc6970" - integrity sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ== - -commander@^9.3.0: - version "9.3.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-9.3.0.tgz#f619114a5a2d2054e0d9ff1b31d5ccf89255e26b" - integrity sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -cosmiconfig@^5.0.7: - version "5.2.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" - integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== - dependencies: - import-fresh "^2.0.0" - is-directory "^0.3.1" - js-yaml "^3.13.1" - parse-json "^4.0.0" - -cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -debug@^4.0.1: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - -debug@^4.3.1, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -deep-extend@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - -deep-is@~0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -eastasianwidth@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" - integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== - -emoji-regex@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.0.0.tgz#96559e19f82231b436403e059571241d627c42b8" - integrity sha512-KmJa8l6uHi1HrBI34udwlzZY1jOEuID/ft4d8BSSEdRyap7PwBEt910453PJa5MuGvxkLqlt4Uvhu7tttFHViw== - -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -emoji-regex@^9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" - integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -eslint-scope@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" - integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-utils@^1.3.1: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint@^5.6.0: - version "5.16.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" - integrity sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg== + "integrity" "sha512-QzSuZMBuG5u8HqYz01qtMdg/Jfctlnvj1z/lYnIDXs/golxw0fxtRAHd9KrzjR7Yxz1qVeI00o0kiO3PmVdJ9w==" + "resolved" "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.3.tgz" + "version" "2.4.3" + +"acorn-jsx@^5.0.0": + "integrity" "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==" + "resolved" "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + "version" "5.3.2" + +"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", "acorn@^6.0.7": + "integrity" "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" + "resolved" "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz" + "version" "6.4.2" + +"aes-js@3.0.0": + "integrity" "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==" + "resolved" "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz" + "version" "3.0.0" + +"aggregate-error@^3.0.0": + "integrity" "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==" + "resolved" "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "clean-stack" "^2.0.0" + "indent-string" "^4.0.0" + +"ajv@^6.10.2", "ajv@^6.6.1", "ajv@^6.9.1": + "integrity" "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==" + "resolved" "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + "version" "6.12.6" + dependencies: + "fast-deep-equal" "^3.1.1" + "fast-json-stable-stringify" "^2.0.0" + "json-schema-traverse" "^0.4.1" + "uri-js" "^4.2.2" + +"ansi-escapes@^3.2.0": + "integrity" "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==" + "resolved" "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz" + "version" "3.2.0" + +"ansi-escapes@^4.3.0": + "integrity" "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==" + "resolved" "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" + "version" "4.3.2" + dependencies: + "type-fest" "^0.21.3" + +"ansi-regex@^3.0.0": + "integrity" "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= sha512-wFUFA5bg5dviipbQQ32yOQhl6gcJaJXiHE7dvR8VYPG97+J/GNC5FKGepKdEDUFeXRzDxPF1X/Btc8L+v7oqIQ==" + "resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz" + "version" "3.0.0" + +"ansi-regex@^4.1.0": + "integrity" "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + "resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz" + "version" "4.1.0" + +"ansi-regex@^5.0.1": + "integrity" "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + "version" "5.0.1" + +"ansi-regex@^6.0.1": + "integrity" "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" + "resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz" + "version" "6.0.1" + +"ansi-styles@^3.2.0": + "integrity" "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==" + "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + "version" "3.2.1" + dependencies: + "color-convert" "^1.9.0" + +"ansi-styles@^3.2.1": + "integrity" "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==" + "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + "version" "3.2.1" + dependencies: + "color-convert" "^1.9.0" + +"ansi-styles@^4.0.0": + "integrity" "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==" + "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + "version" "4.3.0" + dependencies: + "color-convert" "^2.0.1" + +"ansi-styles@^4.1.0": + "integrity" "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==" + "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + "version" "4.3.0" + dependencies: + "color-convert" "^2.0.1" + +"ansi-styles@^6.0.0": + "integrity" "sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==" + "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.0.tgz" + "version" "6.1.0" + +"antlr4@4.7.1": + "integrity" "sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ==" + "resolved" "https://registry.npmjs.org/antlr4/-/antlr4-4.7.1.tgz" + "version" "4.7.1" + +"antlr4ts@^0.5.0-alpha.4": + "integrity" "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==" + "resolved" "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz" + "version" "0.5.0-alpha.4" + +"argparse@^1.0.7": + "integrity" "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==" + "resolved" "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" + "version" "1.0.10" + dependencies: + "sprintf-js" "~1.0.2" + +"array-back@^3.0.1", "array-back@^3.1.0": + "integrity" "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==" + "resolved" "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz" + "version" "3.1.0" + +"array-back@^4.0.1": + "integrity" "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==" + "resolved" "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz" + "version" "4.0.2" + +"ast-parents@0.0.1": + "integrity" "sha1-UI/Q8F0MSHddnszaLhdEIyYejdM= sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==" + "resolved" "https://registry.npmjs.org/ast-parents/-/ast-parents-0.0.1.tgz" + "version" "0.0.1" + +"astral-regex@^1.0.0": + "integrity" "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==" + "resolved" "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz" + "version" "1.0.0" + +"astral-regex@^2.0.0": + "integrity" "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" + "resolved" "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz" + "version" "2.0.0" + +"balanced-match@^1.0.0": + "integrity" "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "resolved" "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + "version" "1.0.2" + +"bech32@1.1.4": + "integrity" "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" + "resolved" "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz" + "version" "1.1.4" + +"bn.js@^4.11.9": + "integrity" "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "resolved" "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" + "version" "4.12.0" + +"bn.js@^5.2.1": + "integrity" "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + "resolved" "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz" + "version" "5.2.1" + +"brace-expansion@^1.1.7": + "integrity" "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==" + "resolved" "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + "version" "1.1.11" + dependencies: + "balanced-match" "^1.0.0" + "concat-map" "0.0.1" + +"braces@^3.0.2": + "integrity" "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==" + "resolved" "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" + "version" "3.0.2" + dependencies: + "fill-range" "^7.0.1" + +"brorand@^1.1.0": + "integrity" "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + "resolved" "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz" + "version" "1.1.0" + +"caller-callsite@^2.0.0": + "integrity" "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==" + "resolved" "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "callsites" "^2.0.0" + +"caller-path@^2.0.0": + "integrity" "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==" + "resolved" "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "caller-callsite" "^2.0.0" + +"callsites@^2.0.0": + "integrity" "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==" + "resolved" "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz" + "version" "2.0.0" + +"callsites@^3.0.0": + "integrity" "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + "resolved" "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + "version" "3.1.0" + +"chalk@^2.0.0", "chalk@^2.1.0", "chalk@^2.4.2": + "integrity" "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==" + "resolved" "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + "version" "2.4.2" + dependencies: + "ansi-styles" "^3.2.1" + "escape-string-regexp" "^1.0.5" + "supports-color" "^5.3.0" + +"chalk@^4.1.0": + "integrity" "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==" + "resolved" "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + "version" "4.1.2" + dependencies: + "ansi-styles" "^4.1.0" + "supports-color" "^7.1.0" + +"chardet@^0.7.0": + "integrity" "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + "resolved" "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz" + "version" "0.7.0" + +"clean-stack@^2.0.0": + "integrity" "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" + "resolved" "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz" + "version" "2.2.0" + +"cli-cursor@^2.1.0": + "integrity" "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==" + "resolved" "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz" + "version" "2.1.0" + dependencies: + "restore-cursor" "^2.0.0" + +"cli-cursor@^3.1.0": + "integrity" "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==" + "resolved" "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "restore-cursor" "^3.1.0" + +"cli-truncate@^2.1.0": + "integrity" "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==" + "resolved" "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz" + "version" "2.1.0" + dependencies: + "slice-ansi" "^3.0.0" + "string-width" "^4.2.0" + +"cli-truncate@^3.1.0": + "integrity" "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==" + "resolved" "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "slice-ansi" "^5.0.0" + "string-width" "^5.0.0" + +"cli-width@^2.0.0": + "integrity" "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==" + "resolved" "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz" + "version" "2.2.1" + +"color-convert@^1.9.0": + "integrity" "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==" + "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + "version" "1.9.3" + dependencies: + "color-name" "1.1.3" + +"color-convert@^2.0.1": + "integrity" "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==" + "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + "version" "2.0.1" + dependencies: + "color-name" "~1.1.4" + +"color-name@~1.1.4": + "integrity" "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + "version" "1.1.4" + +"color-name@1.1.3": + "integrity" "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + "version" "1.1.3" + +"colorette@^2.0.16": + "integrity" "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==" + "resolved" "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz" + "version" "2.0.16" + +"command-line-args@^5.1.1": + "integrity" "sha512-4zqtU1hYsSJzcJBOcNZIbW5Fbk9BkjCp1pZVhQKoRaWL5J7N4XphDLwo8aWwdQpTugxwu+jf9u2ZhkXiqp5Z6A==" + "resolved" "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.0.tgz" + "version" "5.2.0" + dependencies: + "array-back" "^3.1.0" + "find-replace" "^3.0.0" + "lodash.camelcase" "^4.3.0" + "typical" "^4.0.0" + +"command-line-usage@^6.1.0": + "integrity" "sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA==" + "resolved" "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.1.tgz" + "version" "6.1.1" + dependencies: + "array-back" "^4.0.1" + "chalk" "^2.4.2" + "table-layout" "^1.0.1" + "typical" "^5.2.0" + +"commander@^9.3.0": + "integrity" "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==" + "resolved" "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz" + "version" "9.3.0" + +"commander@2.18.0": + "integrity" "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==" + "resolved" "https://registry.npmjs.org/commander/-/commander-2.18.0.tgz" + "version" "2.18.0" + +"concat-map@0.0.1": + "integrity" "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "resolved" "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + "version" "0.0.1" + +"cosmiconfig@^5.0.7": + "integrity" "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==" + "resolved" "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz" + "version" "5.2.1" + dependencies: + "import-fresh" "^2.0.0" + "is-directory" "^0.3.1" + "js-yaml" "^3.13.1" + "parse-json" "^4.0.0" + +"cross-spawn@^6.0.5": + "integrity" "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==" + "resolved" "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz" + "version" "6.0.5" + dependencies: + "nice-try" "^1.0.4" + "path-key" "^2.0.1" + "semver" "^5.5.0" + "shebang-command" "^1.2.0" + "which" "^1.2.9" + +"cross-spawn@^7.0.3": + "integrity" "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==" + "resolved" "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" + "version" "7.0.3" + dependencies: + "path-key" "^3.1.0" + "shebang-command" "^2.0.0" + "which" "^2.0.1" + +"debug@^4.0.1", "debug@^4.3.1", "debug@^4.3.4": + "integrity" "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==" + "resolved" "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + "version" "4.3.4" + dependencies: + "ms" "2.1.2" + +"deep-extend@~0.6.0": + "integrity" "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + "resolved" "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz" + "version" "0.6.0" + +"deep-is@~0.1.3": + "integrity" "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + "resolved" "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" + "version" "0.1.4" + +"doctrine@^3.0.0": + "integrity" "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==" + "resolved" "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "esutils" "^2.0.2" + +"eastasianwidth@^0.2.0": + "integrity" "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + "resolved" "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz" + "version" "0.2.0" + +"elliptic@6.5.4": + "integrity" "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==" + "resolved" "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz" + "version" "6.5.4" + dependencies: + "bn.js" "^4.11.9" + "brorand" "^1.1.0" + "hash.js" "^1.0.0" + "hmac-drbg" "^1.0.1" + "inherits" "^2.0.4" + "minimalistic-assert" "^1.0.1" + "minimalistic-crypto-utils" "^1.0.1" + +"emoji-regex@^10.0.0": + "integrity" "sha512-KmJa8l6uHi1HrBI34udwlzZY1jOEuID/ft4d8BSSEdRyap7PwBEt910453PJa5MuGvxkLqlt4Uvhu7tttFHViw==" + "resolved" "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.0.0.tgz" + "version" "10.0.0" + +"emoji-regex@^7.0.1": + "integrity" "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + "resolved" "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz" + "version" "7.0.3" + +"emoji-regex@^8.0.0": + "integrity" "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "resolved" "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + "version" "8.0.0" + +"emoji-regex@^9.2.2": + "integrity" "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + "resolved" "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz" + "version" "9.2.2" + +"error-ex@^1.3.1": + "integrity" "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==" + "resolved" "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" + "version" "1.3.2" + dependencies: + "is-arrayish" "^0.2.1" + +"escape-string-regexp@^1.0.5": + "integrity" "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + "version" "1.0.5" + +"escape-string-regexp@^4.0.0": + "integrity" "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" + "version" "4.0.0" + +"eslint-scope@^4.0.3": + "integrity" "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==" + "resolved" "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz" + "version" "4.0.3" + dependencies: + "esrecurse" "^4.1.0" + "estraverse" "^4.1.1" + +"eslint-utils@^1.3.1": + "integrity" "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==" + "resolved" "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz" + "version" "1.4.3" + dependencies: + "eslint-visitor-keys" "^1.1.0" + +"eslint-visitor-keys@^1.0.0", "eslint-visitor-keys@^1.1.0": + "integrity" "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" + "resolved" "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" + "version" "1.3.0" + +"eslint@^5.6.0": + "integrity" "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==" + "resolved" "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz" + "version" "5.16.0" dependencies: "@babel/code-frame" "^7.0.0" - ajv "^6.9.1" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" - doctrine "^3.0.0" - eslint-scope "^4.0.3" - eslint-utils "^1.3.1" - eslint-visitor-keys "^1.0.0" - espree "^5.0.1" - esquery "^1.0.1" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob "^7.1.2" - globals "^11.7.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - inquirer "^6.2.2" - js-yaml "^3.13.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.11" - minimatch "^3.0.4" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" - progress "^2.0.0" - regexpp "^2.0.1" - semver "^5.5.1" - strip-ansi "^4.0.0" - strip-json-comments "^2.0.1" - table "^5.2.3" - text-table "^0.2.0" - -espree@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" - integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A== - dependencies: - acorn "^6.0.7" - acorn-jsx "^5.0.0" - eslint-visitor-keys "^1.0.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.0.1: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -execa@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -fast-deep-equal@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-diff@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== - dependencies: - flat-cache "^2.0.1" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -find-replace@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38" - integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ== - dependencies: - array-back "^3.0.1" - -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== - dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" - -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== - -fs-extra@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" - integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - -glob@7.1.7: - version "7.1.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.1.2, glob@^7.1.3: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^11.7.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -graceful-fs@^4.1.2, graceful-fs@^4.1.6: - version "4.2.9" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" - integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -husky@^7.0.0: - version "7.0.4" - resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.4.tgz#242048245dc49c8fb1bf0cc7cfb98dd722531535" - integrity sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ== - -iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -import-fresh@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" - integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= - dependencies: - caller-path "^2.0.0" - resolve-from "^3.0.0" - -import-fresh@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -inquirer@^6.2.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" - integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== - dependencies: - ansi-escapes "^3.2.0" - chalk "^2.4.2" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^3.0.3" - figures "^2.0.0" - lodash "^4.17.12" - mute-stream "0.0.7" - run-async "^2.2.0" - rxjs "^6.4.0" - string-width "^2.1.0" - strip-ansi "^5.1.0" - through "^2.3.6" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - -is-directory@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-fullwidth-code-point@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" - integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -js-sha3@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" - integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.12.0, js-yaml@^3.13.0, js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + "ajv" "^6.9.1" + "chalk" "^2.1.0" + "cross-spawn" "^6.0.5" + "debug" "^4.0.1" + "doctrine" "^3.0.0" + "eslint-scope" "^4.0.3" + "eslint-utils" "^1.3.1" + "eslint-visitor-keys" "^1.0.0" + "espree" "^5.0.1" + "esquery" "^1.0.1" + "esutils" "^2.0.2" + "file-entry-cache" "^5.0.1" + "functional-red-black-tree" "^1.0.1" + "glob" "^7.1.2" + "globals" "^11.7.0" + "ignore" "^4.0.6" + "import-fresh" "^3.0.0" + "imurmurhash" "^0.1.4" + "inquirer" "^6.2.2" + "js-yaml" "^3.13.0" + "json-stable-stringify-without-jsonify" "^1.0.1" + "levn" "^0.3.0" + "lodash" "^4.17.11" + "minimatch" "^3.0.4" + "mkdirp" "^0.5.1" + "natural-compare" "^1.4.0" + "optionator" "^0.8.2" + "path-is-inside" "^1.0.2" + "progress" "^2.0.0" + "regexpp" "^2.0.1" + "semver" "^5.5.1" + "strip-ansi" "^4.0.0" + "strip-json-comments" "^2.0.1" + "table" "^5.2.3" + "text-table" "^0.2.0" + +"espree@^5.0.1": + "integrity" "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==" + "resolved" "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz" + "version" "5.0.1" + dependencies: + "acorn" "^6.0.7" + "acorn-jsx" "^5.0.0" + "eslint-visitor-keys" "^1.0.0" + +"esprima@^4.0.0": + "integrity" "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + "resolved" "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" + "version" "4.0.1" + +"esquery@^1.0.1": + "integrity" "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==" + "resolved" "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz" + "version" "1.4.0" + dependencies: + "estraverse" "^5.1.0" + +"esrecurse@^4.1.0": + "integrity" "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==" + "resolved" "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" + "version" "4.3.0" + dependencies: + "estraverse" "^5.2.0" + +"estraverse@^4.1.1": + "integrity" "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" + "version" "4.3.0" + +"estraverse@^5.1.0": + "integrity" "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + "version" "5.3.0" + +"estraverse@^5.2.0": + "integrity" "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + "version" "5.3.0" + +"esutils@^2.0.2": + "integrity" "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + "resolved" "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + "version" "2.0.3" + +"ethers@^5.1.3": + "integrity" "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==" + "resolved" "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz" + "version" "5.7.2" + dependencies: + "@ethersproject/abi" "5.7.0" + "@ethersproject/abstract-provider" "5.7.0" + "@ethersproject/abstract-signer" "5.7.0" + "@ethersproject/address" "5.7.0" + "@ethersproject/base64" "5.7.0" + "@ethersproject/basex" "5.7.0" + "@ethersproject/bignumber" "5.7.0" + "@ethersproject/bytes" "5.7.0" + "@ethersproject/constants" "5.7.0" + "@ethersproject/contracts" "5.7.0" + "@ethersproject/hash" "5.7.0" + "@ethersproject/hdnode" "5.7.0" + "@ethersproject/json-wallets" "5.7.0" + "@ethersproject/keccak256" "5.7.0" + "@ethersproject/logger" "5.7.0" + "@ethersproject/networks" "5.7.1" + "@ethersproject/pbkdf2" "5.7.0" + "@ethersproject/properties" "5.7.0" + "@ethersproject/providers" "5.7.2" + "@ethersproject/random" "5.7.0" + "@ethersproject/rlp" "5.7.0" + "@ethersproject/sha2" "5.7.0" + "@ethersproject/signing-key" "5.7.0" + "@ethersproject/solidity" "5.7.0" + "@ethersproject/strings" "5.7.0" + "@ethersproject/transactions" "5.7.0" + "@ethersproject/units" "5.7.0" + "@ethersproject/wallet" "5.7.0" + "@ethersproject/web" "5.7.1" + "@ethersproject/wordlists" "5.7.0" + +"execa@^5.1.1": + "integrity" "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==" + "resolved" "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" + "version" "5.1.1" + dependencies: + "cross-spawn" "^7.0.3" + "get-stream" "^6.0.0" + "human-signals" "^2.1.0" + "is-stream" "^2.0.0" + "merge-stream" "^2.0.0" + "npm-run-path" "^4.0.1" + "onetime" "^5.1.2" + "signal-exit" "^3.0.3" + "strip-final-newline" "^2.0.0" + +"external-editor@^3.0.3": + "integrity" "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==" + "resolved" "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "chardet" "^0.7.0" + "iconv-lite" "^0.4.24" + "tmp" "^0.0.33" + +"fast-deep-equal@^3.1.1": + "integrity" "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "resolved" "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" + "version" "3.1.3" + +"fast-diff@^1.1.2": + "integrity" "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==" + "resolved" "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz" + "version" "1.2.0" + +"fast-json-stable-stringify@^2.0.0": + "integrity" "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "resolved" "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + "version" "2.1.0" + +"fast-levenshtein@~2.0.6": + "integrity" "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + "resolved" "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + "version" "2.0.6" + +"figures@^2.0.0": + "integrity" "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==" + "resolved" "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "escape-string-regexp" "^1.0.5" + +"file-entry-cache@^5.0.1": + "integrity" "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==" + "resolved" "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz" + "version" "5.0.1" + dependencies: + "flat-cache" "^2.0.1" + +"fill-range@^7.0.1": + "integrity" "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==" + "resolved" "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" + "version" "7.0.1" + dependencies: + "to-regex-range" "^5.0.1" + +"find-replace@^3.0.0": + "integrity" "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==" + "resolved" "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "array-back" "^3.0.1" + +"flat-cache@^2.0.1": + "integrity" "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==" + "resolved" "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz" + "version" "2.0.1" + dependencies: + "flatted" "^2.0.0" + "rimraf" "2.6.3" + "write" "1.0.3" + +"flatted@^2.0.0": + "integrity" "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==" + "resolved" "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz" + "version" "2.0.2" + +"fs-extra@^7.0.0": + "integrity" "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==" + "resolved" "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz" + "version" "7.0.1" + dependencies: + "graceful-fs" "^4.1.2" + "jsonfile" "^4.0.0" + "universalify" "^0.1.0" + +"fs.realpath@^1.0.0": + "integrity" "sha1-FQStJSMVjKpA20onh8sBQRmU6k8= sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + "resolved" "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + "version" "1.0.0" + +"functional-red-black-tree@^1.0.1": + "integrity" "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==" + "resolved" "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz" + "version" "1.0.1" + +"get-stream@^6.0.0": + "integrity" "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" + "resolved" "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" + "version" "6.0.1" + +"glob@^7.1.2", "glob@^7.1.3": + "integrity" "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==" + "resolved" "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz" + "version" "7.2.0" + dependencies: + "fs.realpath" "^1.0.0" + "inflight" "^1.0.4" + "inherits" "2" + "minimatch" "^3.0.4" + "once" "^1.3.0" + "path-is-absolute" "^1.0.0" + +"glob@7.1.7": + "integrity" "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==" + "resolved" "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz" + "version" "7.1.7" + dependencies: + "fs.realpath" "^1.0.0" + "inflight" "^1.0.4" + "inherits" "2" + "minimatch" "^3.0.4" + "once" "^1.3.0" + "path-is-absolute" "^1.0.0" + +"globals@^11.7.0": + "integrity" "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + "resolved" "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + "version" "11.12.0" + +"graceful-fs@^4.1.2", "graceful-fs@^4.1.6": + "integrity" "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" + "resolved" "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz" + "version" "4.2.9" + +"has-flag@^3.0.0": + "integrity" "sha1-tdRU3CGZriJWmfNGfloH87lVuv0= sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + "version" "3.0.0" + +"has-flag@^4.0.0": + "integrity" "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + "version" "4.0.0" + +"hash.js@^1.0.0", "hash.js@^1.0.3", "hash.js@1.1.7": + "integrity" "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==" + "resolved" "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz" + "version" "1.1.7" + dependencies: + "inherits" "^2.0.3" + "minimalistic-assert" "^1.0.1" + +"hmac-drbg@^1.0.1": + "integrity" "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==" + "resolved" "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "hash.js" "^1.0.3" + "minimalistic-assert" "^1.0.0" + "minimalistic-crypto-utils" "^1.0.1" + +"human-signals@^2.1.0": + "integrity" "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" + "resolved" "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" + "version" "2.1.0" + +"husky@^7.0.0": + "integrity" "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==" + "resolved" "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz" + "version" "7.0.4" + +"iconv-lite@^0.4.24": + "integrity" "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==" + "resolved" "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" + "version" "0.4.24" + dependencies: + "safer-buffer" ">= 2.1.2 < 3" + +"ignore@^4.0.6": + "integrity" "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" + "resolved" "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz" + "version" "4.0.6" + +"import-fresh@^2.0.0": + "integrity" "sha1-2BNVwVYS04bGH53dOSLUMEgipUY= sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==" + "resolved" "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "caller-path" "^2.0.0" + "resolve-from" "^3.0.0" + +"import-fresh@^3.0.0": + "integrity" "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==" + "resolved" "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" + "version" "3.3.0" + dependencies: + "parent-module" "^1.0.0" + "resolve-from" "^4.0.0" + +"imurmurhash@^0.1.4": + "integrity" "sha1-khi5srkoojixPcT7a21XbyMUU+o= sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" + "resolved" "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + "version" "0.1.4" + +"indent-string@^4.0.0": + "integrity" "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + "resolved" "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" + "version" "4.0.0" + +"inflight@^1.0.4": + "integrity" "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==" + "resolved" "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + "version" "1.0.6" + dependencies: + "once" "^1.3.0" + "wrappy" "1" + +"inherits@^2.0.3", "inherits@^2.0.4", "inherits@2": + "integrity" "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "resolved" "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + "version" "2.0.4" + +"inquirer@^6.2.2": + "integrity" "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==" + "resolved" "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz" + "version" "6.5.2" + dependencies: + "ansi-escapes" "^3.2.0" + "chalk" "^2.4.2" + "cli-cursor" "^2.1.0" + "cli-width" "^2.0.0" + "external-editor" "^3.0.3" + "figures" "^2.0.0" + "lodash" "^4.17.12" + "mute-stream" "0.0.7" + "run-async" "^2.2.0" + "rxjs" "^6.4.0" + "string-width" "^2.1.0" + "strip-ansi" "^5.1.0" + "through" "^2.3.6" + +"is-arrayish@^0.2.1": + "integrity" "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + "resolved" "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" + "version" "0.2.1" + +"is-directory@^0.3.1": + "integrity" "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==" + "resolved" "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz" + "version" "0.3.1" + +"is-fullwidth-code-point@^2.0.0": + "integrity" "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" + "resolved" "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz" + "version" "2.0.0" + +"is-fullwidth-code-point@^3.0.0": + "integrity" "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "resolved" "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + "version" "3.0.0" + +"is-fullwidth-code-point@^4.0.0": + "integrity" "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==" + "resolved" "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz" + "version" "4.0.0" + +"is-number@^7.0.0": + "integrity" "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + "resolved" "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + "version" "7.0.0" + +"is-stream@^2.0.0": + "integrity" "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + "resolved" "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" + "version" "2.0.1" + +"isexe@^2.0.0": + "integrity" "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "resolved" "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + "version" "2.0.0" + +"js-sha3@^0.8.0", "js-sha3@0.8.0": + "integrity" "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + "resolved" "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz" + "version" "0.8.0" + +"js-tokens@^4.0.0": + "integrity" "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "resolved" "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + "version" "4.0.0" + +"js-yaml@^3.12.0", "js-yaml@^3.13.0", "js-yaml@^3.13.1": + "integrity" "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==" + "resolved" "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" + "version" "3.14.1" + dependencies: + "argparse" "^1.0.7" + "esprima" "^4.0.0" + +"json-parse-better-errors@^1.0.1": + "integrity" "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + "resolved" "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz" + "version" "1.0.2" + +"json-schema-traverse@^0.4.1": + "integrity" "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "resolved" "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" + "version" "0.4.1" + +"json-stable-stringify-without-jsonify@^1.0.1": + "integrity" "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" + "resolved" "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" + "version" "1.0.1" + +"jsonfile@^4.0.0": + "integrity" "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==" + "resolved" "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz" + "version" "4.0.0" optionalDependencies: - graceful-fs "^4.1.6" - -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -lilconfig@2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.5.tgz#19e57fd06ccc3848fd1891655b5a447092225b25" - integrity sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg== - -lint-staged@^12.3.7: - version "12.5.0" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-12.5.0.tgz#d6925747480ae0e380d13988522f9dd8ef9126e3" - integrity sha512-BKLUjWDsKquV/JuIcoQW4MSAI3ggwEImF1+sB4zaKvyVx1wBk3FsG7UK9bpnmBTN1pm7EH2BBcMwINJzCRv12g== - dependencies: - cli-truncate "^3.1.0" - colorette "^2.0.16" - commander "^9.3.0" - debug "^4.3.4" - execa "^5.1.1" - lilconfig "2.0.5" - listr2 "^4.0.5" - micromatch "^4.0.5" - normalize-path "^3.0.0" - object-inspect "^1.12.2" - pidtree "^0.5.0" - string-argv "^0.3.1" - supports-color "^9.2.2" - yaml "^1.10.2" - -listr2@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-4.0.5.tgz#9dcc50221583e8b4c71c43f9c7dfd0ef546b75d5" - integrity sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA== - dependencies: - cli-truncate "^2.1.0" - colorette "^2.0.16" - log-update "^4.0.0" - p-map "^4.0.0" - rfdc "^1.3.0" - rxjs "^7.5.5" - through "^2.3.8" - wrap-ansi "^7.0.0" - -lodash.camelcase@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" - integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= - -lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -log-update@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" - integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== - dependencies: - ansi-escapes "^4.3.0" - cli-cursor "^3.1.0" - slice-ansi "^4.0.0" - wrap-ansi "^6.2.0" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -micromatch@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== - dependencies: - braces "^3.0.2" - picomatch "^2.3.1" - -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -mkdirp@^0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - -mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -normalize-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -object-inspect@^1.12.2: - version "1.12.2" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" - integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= - dependencies: - mimic-fn "^1.0.0" - -onetime@^5.1.0, onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -optionator@^0.8.2: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -p-map@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" - integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== - dependencies: - aggregate-error "^3.0.0" - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-is-inside@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= - -path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pidtree@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.5.0.tgz#ad5fbc1de78b8a5f99d6fbdd4f6e4eee21d1aca1" - integrity sha512-9nxspIM7OpZuhBxPg73Zvyq7j1QMPMPsGKTqRc2XOaFQauDvoNz9fM1Wdkjmeo7l9GXOZiRs97sPkuayl39wjA== - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - -prettier-plugin-solidity@^1.0.0-beta.19: - version "1.0.0-beta.19" - resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.19.tgz#7c3607fc4028f5e6a425259ff03e45eedf733df3" - integrity sha512-xxRQ5ZiiZyUoMFLE9h7HnUDXI/daf1tnmL1msEdcKmyh7ZGQ4YklkYLC71bfBpYU2WruTb5/SFLUaEb3RApg5g== + "graceful-fs" "^4.1.6" + +"levn@^0.3.0", "levn@~0.3.0": + "integrity" "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==" + "resolved" "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" + "version" "0.3.0" + dependencies: + "prelude-ls" "~1.1.2" + "type-check" "~0.3.2" + +"lilconfig@2.0.5": + "integrity" "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==" + "resolved" "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz" + "version" "2.0.5" + +"lint-staged@^12.3.7": + "integrity" "sha512-BKLUjWDsKquV/JuIcoQW4MSAI3ggwEImF1+sB4zaKvyVx1wBk3FsG7UK9bpnmBTN1pm7EH2BBcMwINJzCRv12g==" + "resolved" "https://registry.npmjs.org/lint-staged/-/lint-staged-12.5.0.tgz" + "version" "12.5.0" + dependencies: + "cli-truncate" "^3.1.0" + "colorette" "^2.0.16" + "commander" "^9.3.0" + "debug" "^4.3.4" + "execa" "^5.1.1" + "lilconfig" "2.0.5" + "listr2" "^4.0.5" + "micromatch" "^4.0.5" + "normalize-path" "^3.0.0" + "object-inspect" "^1.12.2" + "pidtree" "^0.5.0" + "string-argv" "^0.3.1" + "supports-color" "^9.2.2" + "yaml" "^1.10.2" + +"listr2@^4.0.5": + "integrity" "sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==" + "resolved" "https://registry.npmjs.org/listr2/-/listr2-4.0.5.tgz" + "version" "4.0.5" + dependencies: + "cli-truncate" "^2.1.0" + "colorette" "^2.0.16" + "log-update" "^4.0.0" + "p-map" "^4.0.0" + "rfdc" "^1.3.0" + "rxjs" "^7.5.5" + "through" "^2.3.8" + "wrap-ansi" "^7.0.0" + +"lodash.camelcase@^4.3.0": + "integrity" "sha1-soqmKIorn8ZRA1x3EfZathkDMaY= sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + "resolved" "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz" + "version" "4.3.0" + +"lodash@^4.17.11", "lodash@^4.17.12", "lodash@^4.17.14", "lodash@^4.17.15": + "integrity" "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "resolved" "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + "version" "4.17.21" + +"log-update@^4.0.0": + "integrity" "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==" + "resolved" "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz" + "version" "4.0.0" + dependencies: + "ansi-escapes" "^4.3.0" + "cli-cursor" "^3.1.0" + "slice-ansi" "^4.0.0" + "wrap-ansi" "^6.2.0" + +"lru-cache@^6.0.0": + "integrity" "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==" + "resolved" "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" + "version" "6.0.0" + dependencies: + "yallist" "^4.0.0" + +"merge-stream@^2.0.0": + "integrity" "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + "resolved" "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" + "version" "2.0.0" + +"micromatch@^4.0.5": + "integrity" "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==" + "resolved" "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" + "version" "4.0.5" + dependencies: + "braces" "^3.0.2" + "picomatch" "^2.3.1" + +"mimic-fn@^1.0.0": + "integrity" "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" + "resolved" "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz" + "version" "1.2.0" + +"mimic-fn@^2.1.0": + "integrity" "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + "resolved" "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" + "version" "2.1.0" + +"minimalistic-assert@^1.0.0", "minimalistic-assert@^1.0.1": + "integrity" "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + "resolved" "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" + "version" "1.0.1" + +"minimalistic-crypto-utils@^1.0.1": + "integrity" "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + "resolved" "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz" + "version" "1.0.1" + +"minimatch@^3.0.4": + "integrity" "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==" + "resolved" "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz" + "version" "3.0.4" + dependencies: + "brace-expansion" "^1.1.7" + +"minimist@^1.2.5": + "integrity" "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "resolved" "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz" + "version" "1.2.5" + +"mkdirp@^0.5.1": + "integrity" "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==" + "resolved" "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz" + "version" "0.5.5" + dependencies: + "minimist" "^1.2.5" + +"mkdirp@^1.0.4": + "integrity" "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + "resolved" "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" + "version" "1.0.4" + +"ms@2.1.2": + "integrity" "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + "version" "2.1.2" + +"mute-stream@0.0.7": + "integrity" "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==" + "resolved" "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz" + "version" "0.0.7" + +"natural-compare@^1.4.0": + "integrity" "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + "resolved" "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + "version" "1.4.0" + +"nice-try@^1.0.4": + "integrity" "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + "resolved" "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz" + "version" "1.0.5" + +"normalize-path@^3.0.0": + "integrity" "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + "resolved" "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" + "version" "3.0.0" + +"npm-run-path@^4.0.1": + "integrity" "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==" + "resolved" "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" + "version" "4.0.1" + dependencies: + "path-key" "^3.0.0" + +"object-inspect@^1.12.2": + "integrity" "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + "resolved" "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz" + "version" "1.12.2" + +"once@^1.3.0": + "integrity" "sha1-WDsap3WWHUsROsF9nFC6753Xa9E= sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==" + "resolved" "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + "version" "1.4.0" + dependencies: + "wrappy" "1" + +"onetime@^2.0.0": + "integrity" "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==" + "resolved" "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz" + "version" "2.0.1" + dependencies: + "mimic-fn" "^1.0.0" + +"onetime@^5.1.0", "onetime@^5.1.2": + "integrity" "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==" + "resolved" "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" + "version" "5.1.2" + dependencies: + "mimic-fn" "^2.1.0" + +"optionator@^0.8.2": + "integrity" "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==" + "resolved" "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz" + "version" "0.8.3" + dependencies: + "deep-is" "~0.1.3" + "fast-levenshtein" "~2.0.6" + "levn" "~0.3.0" + "prelude-ls" "~1.1.2" + "type-check" "~0.3.2" + "word-wrap" "~1.2.3" + +"os-tmpdir@~1.0.2": + "integrity" "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" + "resolved" "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz" + "version" "1.0.2" + +"p-map@^4.0.0": + "integrity" "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==" + "resolved" "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz" + "version" "4.0.0" + dependencies: + "aggregate-error" "^3.0.0" + +"parent-module@^1.0.0": + "integrity" "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==" + "resolved" "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "callsites" "^3.0.0" + +"parse-json@^4.0.0": + "integrity" "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==" + "resolved" "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz" + "version" "4.0.0" + dependencies: + "error-ex" "^1.3.1" + "json-parse-better-errors" "^1.0.1" + +"path-is-absolute@^1.0.0": + "integrity" "sha1-F0uSaHNVNP+8es5r9TpanhtcX18= sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + "resolved" "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + "version" "1.0.1" + +"path-is-inside@^1.0.2": + "integrity" "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==" + "resolved" "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz" + "version" "1.0.2" + +"path-key@^2.0.1": + "integrity" "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==" + "resolved" "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz" + "version" "2.0.1" + +"path-key@^3.0.0", "path-key@^3.1.0": + "integrity" "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + "resolved" "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + "version" "3.1.1" + +"picomatch@^2.3.1": + "integrity" "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + "resolved" "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + "version" "2.3.1" + +"pidtree@^0.5.0": + "integrity" "sha512-9nxspIM7OpZuhBxPg73Zvyq7j1QMPMPsGKTqRc2XOaFQauDvoNz9fM1Wdkjmeo7l9GXOZiRs97sPkuayl39wjA==" + "resolved" "https://registry.npmjs.org/pidtree/-/pidtree-0.5.0.tgz" + "version" "0.5.0" + +"prelude-ls@~1.1.2": + "integrity" "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==" + "resolved" "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" + "version" "1.1.2" + +"prettier-linter-helpers@^1.0.0": + "integrity" "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==" + "resolved" "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "fast-diff" "^1.1.2" + +"prettier-plugin-solidity@^1.0.0-alpha.14", "prettier-plugin-solidity@^1.0.0-beta.19": + "integrity" "sha512-xxRQ5ZiiZyUoMFLE9h7HnUDXI/daf1tnmL1msEdcKmyh7ZGQ4YklkYLC71bfBpYU2WruTb5/SFLUaEb3RApg5g==" + "resolved" "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.19.tgz" + "version" "1.0.0-beta.19" dependencies: "@solidity-parser/parser" "^0.14.0" - emoji-regex "^10.0.0" - escape-string-regexp "^4.0.0" - semver "^7.3.5" - solidity-comments-extractor "^0.0.7" - string-width "^4.2.3" - -prettier@^1.14.3: - version "1.19.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" - integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== - -prettier@^2.3.1, prettier@^2.6.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" - integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -reduce-flatten@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27" - integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w== - -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - integrity sha1-six699nWiBvItuZTM17rywoYh0g= - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - -rfdc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" - integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== - -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -run-async@^2.2.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - -rxjs@^6.4.0: - version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== - dependencies: - tslib "^1.9.0" - -rxjs@^7.5.5: - version "7.5.5" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f" - integrity sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw== - dependencies: - tslib "^2.1.0" + "emoji-regex" "^10.0.0" + "escape-string-regexp" "^4.0.0" + "semver" "^7.3.5" + "solidity-comments-extractor" "^0.0.7" + "string-width" "^4.2.3" + +"prettier@^1.14.3": + "integrity" "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==" + "resolved" "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz" + "version" "1.19.1" + +"prettier@^1.15.0 || ^2.0.0", "prettier@^2.3.0", "prettier@^2.3.1", "prettier@^2.6.1": + "integrity" "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==" + "resolved" "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz" + "version" "2.7.1" + +"progress@^2.0.0": + "integrity" "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" + "resolved" "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" + "version" "2.0.3" + +"punycode@^2.1.0": + "integrity" "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "resolved" "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz" + "version" "2.1.1" + +"reduce-flatten@^2.0.0": + "integrity" "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==" + "resolved" "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz" + "version" "2.0.0" + +"regexpp@^2.0.1": + "integrity" "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==" + "resolved" "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz" + "version" "2.0.1" + +"resolve-from@^3.0.0": + "integrity" "sha1-six699nWiBvItuZTM17rywoYh0g= sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==" + "resolved" "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz" + "version" "3.0.0" + +"resolve-from@^4.0.0": + "integrity" "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + "resolved" "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" + "version" "4.0.0" + +"restore-cursor@^2.0.0": + "integrity" "sha1-n37ih/gv0ybU/RYpI9YhKe7g368= sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==" + "resolved" "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "onetime" "^2.0.0" + "signal-exit" "^3.0.2" + +"restore-cursor@^3.1.0": + "integrity" "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==" + "resolved" "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "onetime" "^5.1.0" + "signal-exit" "^3.0.2" + +"rfdc@^1.3.0": + "integrity" "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" + "resolved" "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz" + "version" "1.3.0" + +"rimraf@2.6.3": + "integrity" "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==" + "resolved" "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz" + "version" "2.6.3" + dependencies: + "glob" "^7.1.3" + +"run-async@^2.2.0": + "integrity" "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==" + "resolved" "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz" + "version" "2.4.1" + +"rxjs@^6.4.0": + "integrity" "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==" + "resolved" "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz" + "version" "6.6.7" + dependencies: + "tslib" "^1.9.0" + +"rxjs@^7.5.5": + "integrity" "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==" + "resolved" "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz" + "version" "7.5.5" + dependencies: + "tslib" "^2.1.0" "safer-buffer@>= 2.1.2 < 3": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -semver@^5.5.0, semver@^5.5.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -signal-exit@^3.0.2, signal-exit@^3.0.3: - version "3.0.6" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" - integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== - -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - -slice-ansi@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" - integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - -slice-ansi@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" - integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== - dependencies: - ansi-styles "^6.0.0" - is-fullwidth-code-point "^4.0.0" - -solhint-plugin-prettier@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/solhint-plugin-prettier/-/solhint-plugin-prettier-0.0.5.tgz#e3b22800ba435cd640a9eca805a7f8bc3e3e6a6b" - integrity sha512-7jmWcnVshIrO2FFinIvDQmhQpfpS2rRRn3RejiYgnjIE68xO2bvrYvjqVNfrio4xH9ghOqn83tKuTzLjEbmGIA== - dependencies: - prettier-linter-helpers "^1.0.0" - -solhint@^3.3.7: - version "3.3.7" - resolved "https://registry.yarnpkg.com/solhint/-/solhint-3.3.7.tgz#b5da4fedf7a0fee954cb613b6c55a5a2b0063aa7" - integrity sha512-NjjjVmXI3ehKkb3aNtRJWw55SUVJ8HMKKodwe0HnejA+k0d2kmhw7jvpa+MCTbcEgt8IWSwx0Hu6aCo/iYOZzQ== + "integrity" "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "resolved" "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" + "version" "2.1.2" + +"scrypt-js@3.0.1": + "integrity" "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" + "resolved" "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz" + "version" "3.0.1" + +"semver@^5.5.0", "semver@^5.5.1": + "integrity" "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "resolved" "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" + "version" "5.7.1" + +"semver@^6.3.0": + "integrity" "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "resolved" "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" + "version" "6.3.0" + +"semver@^7.3.5": + "integrity" "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==" + "resolved" "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz" + "version" "7.3.5" + dependencies: + "lru-cache" "^6.0.0" + +"shebang-command@^1.2.0": + "integrity" "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==" + "resolved" "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz" + "version" "1.2.0" + dependencies: + "shebang-regex" "^1.0.0" + +"shebang-command@^2.0.0": + "integrity" "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==" + "resolved" "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "shebang-regex" "^3.0.0" + +"shebang-regex@^1.0.0": + "integrity" "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==" + "resolved" "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz" + "version" "1.0.0" + +"shebang-regex@^3.0.0": + "integrity" "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + "resolved" "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + "version" "3.0.0" + +"signal-exit@^3.0.2", "signal-exit@^3.0.3": + "integrity" "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==" + "resolved" "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz" + "version" "3.0.6" + +"slice-ansi@^2.1.0": + "integrity" "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==" + "resolved" "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz" + "version" "2.1.0" + dependencies: + "ansi-styles" "^3.2.0" + "astral-regex" "^1.0.0" + "is-fullwidth-code-point" "^2.0.0" + +"slice-ansi@^3.0.0": + "integrity" "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==" + "resolved" "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "ansi-styles" "^4.0.0" + "astral-regex" "^2.0.0" + "is-fullwidth-code-point" "^3.0.0" + +"slice-ansi@^4.0.0": + "integrity" "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==" + "resolved" "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz" + "version" "4.0.0" + dependencies: + "ansi-styles" "^4.0.0" + "astral-regex" "^2.0.0" + "is-fullwidth-code-point" "^3.0.0" + +"slice-ansi@^5.0.0": + "integrity" "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==" + "resolved" "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz" + "version" "5.0.0" + dependencies: + "ansi-styles" "^6.0.0" + "is-fullwidth-code-point" "^4.0.0" + +"solhint-plugin-prettier@^0.0.5": + "integrity" "sha512-7jmWcnVshIrO2FFinIvDQmhQpfpS2rRRn3RejiYgnjIE68xO2bvrYvjqVNfrio4xH9ghOqn83tKuTzLjEbmGIA==" + "resolved" "https://registry.npmjs.org/solhint-plugin-prettier/-/solhint-plugin-prettier-0.0.5.tgz" + "version" "0.0.5" + dependencies: + "prettier-linter-helpers" "^1.0.0" + +"solhint@^3.3.7": + "integrity" "sha512-NjjjVmXI3ehKkb3aNtRJWw55SUVJ8HMKKodwe0HnejA+k0d2kmhw7jvpa+MCTbcEgt8IWSwx0Hu6aCo/iYOZzQ==" + "resolved" "https://registry.npmjs.org/solhint/-/solhint-3.3.7.tgz" + "version" "3.3.7" dependencies: "@solidity-parser/parser" "^0.14.1" - ajv "^6.6.1" - antlr4 "4.7.1" - ast-parents "0.0.1" - chalk "^2.4.2" - commander "2.18.0" - cosmiconfig "^5.0.7" - eslint "^5.6.0" - fast-diff "^1.1.2" - glob "^7.1.3" - ignore "^4.0.6" - js-yaml "^3.12.0" - lodash "^4.17.11" - semver "^6.3.0" + "ajv" "^6.6.1" + "antlr4" "4.7.1" + "ast-parents" "0.0.1" + "chalk" "^2.4.2" + "commander" "2.18.0" + "cosmiconfig" "^5.0.7" + "eslint" "^5.6.0" + "fast-diff" "^1.1.2" + "glob" "^7.1.3" + "ignore" "^4.0.6" + "js-yaml" "^3.12.0" + "lodash" "^4.17.11" + "semver" "^6.3.0" optionalDependencies: - prettier "^1.14.3" - -solidity-comments-extractor@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz#99d8f1361438f84019795d928b931f4e5c39ca19" - integrity sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw== - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -string-argv@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" - integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== - -string-format@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/string-format/-/string-format-2.0.0.tgz#f2df2e7097440d3b65de31b6d40d54c96eaffb9b" - integrity sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA== - -string-width@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.0.tgz#5ab00980cfb29f43e736b113a120a73a0fb569d3" - integrity sha512-7x54QnN21P+XL/v8SuNKvfgsUre6PXpN7mc77N3HlZv+f1SBRGmjxtOud2Z6FZ8DmdkD/IdjCaf9XXbnqmTZGQ== - dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - -strip-ansi@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" - integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw== - dependencies: - ansi-regex "^6.0.1" - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-json-comments@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-color@^9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-9.2.2.tgz#502acaf82f2b7ee78eb7c83dcac0f89694e5a7bb" - integrity sha512-XC6g/Kgux+rJXmwokjm9ECpD6k/smUoS5LKlUCcsYr4IY3rW0XyAympon2RmxGrlnZURMpg5T18gWDP9CsHXFA== - -table-layout@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04" - integrity sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A== - dependencies: - array-back "^4.0.1" - deep-extend "~0.6.0" - typical "^5.2.0" - wordwrapjs "^4.0.0" - -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -through@^2.3.6, through@^2.3.8: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -ts-command-line-args@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/ts-command-line-args/-/ts-command-line-args-2.2.0.tgz#655e10451b06c86d318e9467546da4d19b773a55" - integrity sha512-RedEejZyhiEAOgBkIVxB4QC/SRYtl98D7b7epWB9e6E+TmK8KstXBu3WdnhGbMHicLkHoG7sCAmu+F+ASzLFHA== - dependencies: - chalk "^4.1.0" - command-line-args "^5.1.1" - command-line-usage "^6.1.0" - string-format "^2.0.0" - -ts-essentials@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-7.0.3.tgz#686fd155a02133eedcc5362dc8b5056cde3e5a38" - integrity sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ== - -tslib@^1.9.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslib@^2.1.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" - -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -typechain@^8.0.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/typechain/-/typechain-8.1.0.tgz#fc4902ce596519cb2ccfd012e4ddf92a9945b569" - integrity sha512-5jToLgKTjHdI1VKqs/K8BLYy42Sr3o8bV5ojh4MnR9ExHO83cyyUdw+7+vMJCpKXUiVUvARM4qmHTFuyaCMAZQ== + "prettier" "^1.14.3" + +"solidity-comments-extractor@^0.0.7": + "integrity" "sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==" + "resolved" "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz" + "version" "0.0.7" + +"sprintf-js@~1.0.2": + "integrity" "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + "resolved" "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + "version" "1.0.3" + +"string-argv@^0.3.1": + "integrity" "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==" + "resolved" "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz" + "version" "0.3.1" + +"string-format@^2.0.0": + "integrity" "sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==" + "resolved" "https://registry.npmjs.org/string-format/-/string-format-2.0.0.tgz" + "version" "2.0.0" + +"string-width@^2.1.0": + "integrity" "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==" + "resolved" "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz" + "version" "2.1.1" + dependencies: + "is-fullwidth-code-point" "^2.0.0" + "strip-ansi" "^4.0.0" + +"string-width@^3.0.0": + "integrity" "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==" + "resolved" "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "emoji-regex" "^7.0.1" + "is-fullwidth-code-point" "^2.0.0" + "strip-ansi" "^5.1.0" + +"string-width@^4.1.0": + "integrity" "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==" + "resolved" "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + "version" "4.2.3" + dependencies: + "emoji-regex" "^8.0.0" + "is-fullwidth-code-point" "^3.0.0" + "strip-ansi" "^6.0.1" + +"string-width@^4.2.0": + "integrity" "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==" + "resolved" "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + "version" "4.2.3" + dependencies: + "emoji-regex" "^8.0.0" + "is-fullwidth-code-point" "^3.0.0" + "strip-ansi" "^6.0.1" + +"string-width@^4.2.3": + "integrity" "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==" + "resolved" "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + "version" "4.2.3" + dependencies: + "emoji-regex" "^8.0.0" + "is-fullwidth-code-point" "^3.0.0" + "strip-ansi" "^6.0.1" + +"string-width@^5.0.0": + "integrity" "sha512-7x54QnN21P+XL/v8SuNKvfgsUre6PXpN7mc77N3HlZv+f1SBRGmjxtOud2Z6FZ8DmdkD/IdjCaf9XXbnqmTZGQ==" + "resolved" "https://registry.npmjs.org/string-width/-/string-width-5.1.0.tgz" + "version" "5.1.0" + dependencies: + "eastasianwidth" "^0.2.0" + "emoji-regex" "^9.2.2" + "strip-ansi" "^7.0.1" + +"strip-ansi@^4.0.0": + "integrity" "sha1-qEeQIusaw2iocTibY1JixQXuNo8= sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==" + "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz" + "version" "4.0.0" + dependencies: + "ansi-regex" "^3.0.0" + +"strip-ansi@^5.1.0": + "integrity" "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==" + "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz" + "version" "5.2.0" + dependencies: + "ansi-regex" "^4.1.0" + +"strip-ansi@^6.0.0", "strip-ansi@^6.0.1": + "integrity" "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==" + "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + "version" "6.0.1" + dependencies: + "ansi-regex" "^5.0.1" + +"strip-ansi@^7.0.1": + "integrity" "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==" + "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz" + "version" "7.0.1" + dependencies: + "ansi-regex" "^6.0.1" + +"strip-final-newline@^2.0.0": + "integrity" "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + "resolved" "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" + "version" "2.0.0" + +"strip-json-comments@^2.0.1": + "integrity" "sha1-PFMZQukIwml8DsNEhYwobHygpgo= sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" + "resolved" "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" + "version" "2.0.1" + +"supports-color@^5.3.0": + "integrity" "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==" + "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + "version" "5.5.0" + dependencies: + "has-flag" "^3.0.0" + +"supports-color@^7.1.0": + "integrity" "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==" + "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + "version" "7.2.0" + dependencies: + "has-flag" "^4.0.0" + +"supports-color@^9.2.2": + "integrity" "sha512-XC6g/Kgux+rJXmwokjm9ECpD6k/smUoS5LKlUCcsYr4IY3rW0XyAympon2RmxGrlnZURMpg5T18gWDP9CsHXFA==" + "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-9.2.2.tgz" + "version" "9.2.2" + +"table-layout@^1.0.1": + "integrity" "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==" + "resolved" "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "array-back" "^4.0.1" + "deep-extend" "~0.6.0" + "typical" "^5.2.0" + "wordwrapjs" "^4.0.0" + +"table@^5.2.3": + "integrity" "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==" + "resolved" "https://registry.npmjs.org/table/-/table-5.4.6.tgz" + "version" "5.4.6" + dependencies: + "ajv" "^6.10.2" + "lodash" "^4.17.14" + "slice-ansi" "^2.1.0" + "string-width" "^3.0.0" + +"text-table@^0.2.0": + "integrity" "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + "resolved" "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + "version" "0.2.0" + +"through@^2.3.6", "through@^2.3.8": + "integrity" "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + "resolved" "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + "version" "2.3.8" + +"tmp@^0.0.33": + "integrity" "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==" + "resolved" "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz" + "version" "0.0.33" + dependencies: + "os-tmpdir" "~1.0.2" + +"to-regex-range@^5.0.1": + "integrity" "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==" + "resolved" "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + "version" "5.0.1" + dependencies: + "is-number" "^7.0.0" + +"ts-command-line-args@^2.2.0": + "integrity" "sha512-RedEejZyhiEAOgBkIVxB4QC/SRYtl98D7b7epWB9e6E+TmK8KstXBu3WdnhGbMHicLkHoG7sCAmu+F+ASzLFHA==" + "resolved" "https://registry.npmjs.org/ts-command-line-args/-/ts-command-line-args-2.2.0.tgz" + "version" "2.2.0" + dependencies: + "chalk" "^4.1.0" + "command-line-args" "^5.1.1" + "command-line-usage" "^6.1.0" + "string-format" "^2.0.0" + +"ts-essentials@^7.0.1": + "integrity" "sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==" + "resolved" "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz" + "version" "7.0.3" + +"tslib@^1.9.0": + "integrity" "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "resolved" "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" + "version" "1.14.1" + +"tslib@^2.1.0": + "integrity" "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "resolved" "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz" + "version" "2.3.1" + +"type-check@~0.3.2": + "integrity" "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==" + "resolved" "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" + "version" "0.3.2" + dependencies: + "prelude-ls" "~1.1.2" + +"type-fest@^0.21.3": + "integrity" "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" + "resolved" "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" + "version" "0.21.3" + +"typechain@^8.0.0", "typechain@^8.1.0": + "integrity" "sha512-5jToLgKTjHdI1VKqs/K8BLYy42Sr3o8bV5ojh4MnR9ExHO83cyyUdw+7+vMJCpKXUiVUvARM4qmHTFuyaCMAZQ==" + "resolved" "https://registry.npmjs.org/typechain/-/typechain-8.1.0.tgz" + "version" "8.1.0" dependencies: "@types/prettier" "^2.1.1" - debug "^4.3.1" - fs-extra "^7.0.0" - glob "7.1.7" - js-sha3 "^0.8.0" - lodash "^4.17.15" - mkdirp "^1.0.4" - prettier "^2.3.1" - ts-command-line-args "^2.2.0" - ts-essentials "^7.0.1" - -typescript@^4.6.3: - version "4.7.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" - integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== - -typical@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" - integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== - -typical@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/typical/-/typical-5.2.0.tgz#4daaac4f2b5315460804f0acf6cb69c52bb93066" - integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg== - -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -wordwrapjs@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-4.0.1.tgz#d9790bccfb110a0fc7836b5ebce0937b37a8b98f" - integrity sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA== - dependencies: - reduce-flatten "^2.0.0" - typical "^5.2.0" - -wrap-ansi@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" - integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yaml@^1.10.2: - version "1.10.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + "debug" "^4.3.1" + "fs-extra" "^7.0.0" + "glob" "7.1.7" + "js-sha3" "^0.8.0" + "lodash" "^4.17.15" + "mkdirp" "^1.0.4" + "prettier" "^2.3.1" + "ts-command-line-args" "^2.2.0" + "ts-essentials" "^7.0.1" + +"typescript@^4.6.3", "typescript@>=3.7.0", "typescript@>=4.3.0": + "integrity" "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==" + "resolved" "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz" + "version" "4.7.4" + +"typical@^4.0.0": + "integrity" "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==" + "resolved" "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz" + "version" "4.0.0" + +"typical@^5.2.0": + "integrity" "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" + "resolved" "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz" + "version" "5.2.0" + +"universalify@^0.1.0": + "integrity" "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + "resolved" "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz" + "version" "0.1.2" + +"uri-js@^4.2.2": + "integrity" "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==" + "resolved" "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" + "version" "4.4.1" + dependencies: + "punycode" "^2.1.0" + +"which@^1.2.9": + "integrity" "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==" + "resolved" "https://registry.npmjs.org/which/-/which-1.3.1.tgz" + "version" "1.3.1" + dependencies: + "isexe" "^2.0.0" + +"which@^2.0.1": + "integrity" "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==" + "resolved" "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + "version" "2.0.2" + dependencies: + "isexe" "^2.0.0" + +"word-wrap@~1.2.3": + "integrity" "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + "resolved" "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz" + "version" "1.2.3" + +"wordwrapjs@^4.0.0": + "integrity" "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==" + "resolved" "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz" + "version" "4.0.1" + dependencies: + "reduce-flatten" "^2.0.0" + "typical" "^5.2.0" + +"wrap-ansi@^6.2.0": + "integrity" "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==" + "resolved" "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz" + "version" "6.2.0" + dependencies: + "ansi-styles" "^4.0.0" + "string-width" "^4.1.0" + "strip-ansi" "^6.0.0" + +"wrap-ansi@^7.0.0": + "integrity" "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==" + "resolved" "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + "version" "7.0.0" + dependencies: + "ansi-styles" "^4.0.0" + "string-width" "^4.1.0" + "strip-ansi" "^6.0.0" + +"wrappy@1": + "integrity" "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "resolved" "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "version" "1.0.2" + +"write@1.0.3": + "integrity" "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==" + "resolved" "https://registry.npmjs.org/write/-/write-1.0.3.tgz" + "version" "1.0.3" + dependencies: + "mkdirp" "^0.5.1" + +"ws@7.4.6": + "integrity" "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" + "resolved" "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz" + "version" "7.4.6" + +"yallist@^4.0.0": + "integrity" "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "resolved" "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + "version" "4.0.0" + +"yaml@^1.10.2": + "integrity" "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + "resolved" "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" + "version" "1.10.2" From 125049e7a6c718a7614e712dad526a3644edb503 Mon Sep 17 00:00:00 2001 From: Rohan2407 Date: Wed, 17 May 2023 09:54:28 +0530 Subject: [PATCH 3/4] updated setup and manifold for canto --- contracts/csr/ITurnstile.sol | 11 + contracts/manifold/FallbackRegistry.sol | 52 - contracts/manifold/IRoyaltyRegistry.sol | 10 +- contracts/manifold/RoyaltyEngineV1.sol | 272 +--- contracts/manifold/RoyaltyRegistry.sol | 59 +- .../manifold/overrides/IFallbackRegistry.sol | 12 - .../IMultiReceiverRoyaltyOverride.sol | 48 - .../manifold/overrides/IRoyaltySplitter.sol | 24 - .../MultiReceiverRoyaltyOverrideCloneable.sol | 42 - .../MultiReceiverRoyaltyOverrideCore.sol | 148 --- .../overrides/RoyaltyOverrideCloneable.sol | 5 +- .../overrides/RoyaltyOverrideFactory.sol | 94 -- .../manifold/overrides/RoyaltySplitter.sol | 194 --- .../modules/Asks/Core/ERC20/AsksCoreErc20.sol | 372 ------ .../Asks/Core/ERC20/IAsksCoreErc20.sol | 48 - .../modules/Asks/Core/ETH/AsksCoreEth.sol | 322 ----- .../modules/Asks/Core/ETH/IAsksCoreEth.sol | 37 - .../modules/Asks/Omnibus/AsksDataStorage.sol | 167 --- .../modules/Asks/Omnibus/AsksOmnibus.sol | 332 ----- .../modules/Asks/Omnibus/IAsksOmnibus.sol | 71 -- .../Asks/Private/ETH/AsksPrivateEth.sol | 333 ----- .../Asks/Private/ETH/IAsksPrivateEth.sol | 39 - contracts/modules/Asks/V1.1/AsksV1_1.sol | 160 ++- .../modules/Offers/Omnibus/IOffersOmnibus.sol | 81 -- .../Offers/Omnibus/OffersDataStorage.sol | 119 -- .../modules/Offers/Omnibus/OffersOmnibus.sol | 328 ----- .../Core/ERC20/IReserveAuctionCoreErc20.sol | 55 - .../Core/ERC20/ReserveAuctionCoreErc20.sol | 541 -------- .../Core/ETH/IReserveAuctionCoreEth.sol | 48 - .../Core/ETH/ReserveAuctionCoreEth.sol | 511 -------- .../ERC20/IReserveAuctionFindersErc20.sol | 59 - .../ERC20/ReserveAuctionFindersErc20.sol | 587 --------- .../Finders/ETH/IReserveAuctionFindersEth.sol | 55 - .../Finders/ETH/ReserveAuctionFindersEth.sol | 555 -------- .../Listing/ETH/IReserveAuctionListingEth.sol | 52 - .../Listing/ETH/ReserveAuctionListingEth.sol | 550 -------- .../Omnibus/IReserveAuctionOmnibus.sol | 93 -- .../Omnibus/ReserveAuctionDataStorage.sol | 201 --- .../Omnibus/ReserveAuctionOmnibus.sol | 504 -------- .../ERC20/AsksCoreErc20.integration.t.sol | 136 -- .../Asks/Core/ERC20/AsksCoreErc20.t.sol | 362 ------ .../Core/ETH/AsksCoreEth.integration.t.sol | 136 -- .../modules/Asks/Core/ETH/AsksCoreEth.t.sol | 322 ----- .../Asks/Omnibus/AsksDataStorage.t.sol | 141 -- .../modules/Asks/Omnibus/AsksOmnibus.t.sol | 636 --------- .../ETH/AsksPrivateEth.integration.t.sol | 131 -- .../Asks/Private/ETH/AsksPrivateEth.t.sol | 333 ----- .../Omnibus/OffersOmnibus.integration.t.sol | 172 --- .../Offers/Omnibus/OffersOmnibus.t.sol | 377 ------ .../ReserveAuctionCoreErc20.t.integration.sol | 169 --- .../Core/ERC20/ReserveAuctionCoreErc20.t.sol | 478 ------- .../ReserveAuctionCoreEth.integration.t.sol | 162 --- .../Core/ETH/ReserveAuctionCoreEth.t.sol | 442 ------- ...serveAuctionFindersErc20.integration.t.sol | 173 --- .../ERC20/ReserveAuctionFindersErc20.t.sol | 492 ------- ...ReserveAuctionFindersEth.integration.t.sol | 163 --- .../ETH/ReserveAuctionFindersEth.t.sol | 455 ------- ...ReserveAuctionListingEth.integration.t.sol | 160 --- .../ETH/ReserveAuctionListingEth.t.sol | 453 ------- .../Omnibus/ReserveAuctionDataStorage.t.sol | 114 -- .../Omnibus/ReserveAuctionOmnibus.t.sol | 1133 ----------------- .../transferHelpers/ERC20TransferHelper.sol | 5 +- .../transferHelpers/ERC721TransferHelper.sol | 5 +- 63 files changed, 207 insertions(+), 14134 deletions(-) create mode 100644 contracts/csr/ITurnstile.sol delete mode 100644 contracts/manifold/FallbackRegistry.sol delete mode 100644 contracts/manifold/overrides/IFallbackRegistry.sol delete mode 100644 contracts/manifold/overrides/IMultiReceiverRoyaltyOverride.sol delete mode 100644 contracts/manifold/overrides/IRoyaltySplitter.sol delete mode 100644 contracts/manifold/overrides/MultiReceiverRoyaltyOverrideCloneable.sol delete mode 100644 contracts/manifold/overrides/MultiReceiverRoyaltyOverrideCore.sol delete mode 100644 contracts/manifold/overrides/RoyaltyOverrideFactory.sol delete mode 100644 contracts/manifold/overrides/RoyaltySplitter.sol delete mode 100644 contracts/modules/Asks/Core/ERC20/AsksCoreErc20.sol delete mode 100644 contracts/modules/Asks/Core/ERC20/IAsksCoreErc20.sol delete mode 100644 contracts/modules/Asks/Core/ETH/AsksCoreEth.sol delete mode 100644 contracts/modules/Asks/Core/ETH/IAsksCoreEth.sol delete mode 100644 contracts/modules/Asks/Omnibus/AsksDataStorage.sol delete mode 100644 contracts/modules/Asks/Omnibus/AsksOmnibus.sol delete mode 100644 contracts/modules/Asks/Omnibus/IAsksOmnibus.sol delete mode 100644 contracts/modules/Asks/Private/ETH/AsksPrivateEth.sol delete mode 100644 contracts/modules/Asks/Private/ETH/IAsksPrivateEth.sol delete mode 100644 contracts/modules/Offers/Omnibus/IOffersOmnibus.sol delete mode 100644 contracts/modules/Offers/Omnibus/OffersDataStorage.sol delete mode 100644 contracts/modules/Offers/Omnibus/OffersOmnibus.sol delete mode 100644 contracts/modules/ReserveAuction/Core/ERC20/IReserveAuctionCoreErc20.sol delete mode 100644 contracts/modules/ReserveAuction/Core/ERC20/ReserveAuctionCoreErc20.sol delete mode 100644 contracts/modules/ReserveAuction/Core/ETH/IReserveAuctionCoreEth.sol delete mode 100644 contracts/modules/ReserveAuction/Core/ETH/ReserveAuctionCoreEth.sol delete mode 100644 contracts/modules/ReserveAuction/Finders/ERC20/IReserveAuctionFindersErc20.sol delete mode 100644 contracts/modules/ReserveAuction/Finders/ERC20/ReserveAuctionFindersErc20.sol delete mode 100644 contracts/modules/ReserveAuction/Finders/ETH/IReserveAuctionFindersEth.sol delete mode 100644 contracts/modules/ReserveAuction/Finders/ETH/ReserveAuctionFindersEth.sol delete mode 100644 contracts/modules/ReserveAuction/Listing/ETH/IReserveAuctionListingEth.sol delete mode 100644 contracts/modules/ReserveAuction/Listing/ETH/ReserveAuctionListingEth.sol delete mode 100644 contracts/modules/ReserveAuction/Omnibus/IReserveAuctionOmnibus.sol delete mode 100644 contracts/modules/ReserveAuction/Omnibus/ReserveAuctionDataStorage.sol delete mode 100644 contracts/modules/ReserveAuction/Omnibus/ReserveAuctionOmnibus.sol delete mode 100644 contracts/test/modules/Asks/Core/ERC20/AsksCoreErc20.integration.t.sol delete mode 100644 contracts/test/modules/Asks/Core/ERC20/AsksCoreErc20.t.sol delete mode 100644 contracts/test/modules/Asks/Core/ETH/AsksCoreEth.integration.t.sol delete mode 100644 contracts/test/modules/Asks/Core/ETH/AsksCoreEth.t.sol delete mode 100644 contracts/test/modules/Asks/Omnibus/AsksDataStorage.t.sol delete mode 100644 contracts/test/modules/Asks/Omnibus/AsksOmnibus.t.sol delete mode 100644 contracts/test/modules/Asks/Private/ETH/AsksPrivateEth.integration.t.sol delete mode 100644 contracts/test/modules/Asks/Private/ETH/AsksPrivateEth.t.sol delete mode 100644 contracts/test/modules/Offers/Omnibus/OffersOmnibus.integration.t.sol delete mode 100644 contracts/test/modules/Offers/Omnibus/OffersOmnibus.t.sol delete mode 100644 contracts/test/modules/ReserveAuction/Core/ERC20/ReserveAuctionCoreErc20.t.integration.sol delete mode 100644 contracts/test/modules/ReserveAuction/Core/ERC20/ReserveAuctionCoreErc20.t.sol delete mode 100644 contracts/test/modules/ReserveAuction/Core/ETH/ReserveAuctionCoreEth.integration.t.sol delete mode 100644 contracts/test/modules/ReserveAuction/Core/ETH/ReserveAuctionCoreEth.t.sol delete mode 100644 contracts/test/modules/ReserveAuction/Finders/ERC20/ReserveAuctionFindersErc20.integration.t.sol delete mode 100644 contracts/test/modules/ReserveAuction/Finders/ERC20/ReserveAuctionFindersErc20.t.sol delete mode 100644 contracts/test/modules/ReserveAuction/Finders/ETH/ReserveAuctionFindersEth.integration.t.sol delete mode 100644 contracts/test/modules/ReserveAuction/Finders/ETH/ReserveAuctionFindersEth.t.sol delete mode 100644 contracts/test/modules/ReserveAuction/Listing/ETH/ReserveAuctionListingEth.integration.t.sol delete mode 100644 contracts/test/modules/ReserveAuction/Listing/ETH/ReserveAuctionListingEth.t.sol delete mode 100644 contracts/test/modules/ReserveAuction/Omnibus/ReserveAuctionDataStorage.t.sol delete mode 100644 contracts/test/modules/ReserveAuction/Omnibus/ReserveAuctionOmnibus.t.sol diff --git a/contracts/csr/ITurnstile.sol b/contracts/csr/ITurnstile.sol new file mode 100644 index 00000000..d50b0fe2 --- /dev/null +++ b/contracts/csr/ITurnstile.sol @@ -0,0 +1,11 @@ +// turnstile address: 0xEcf044C5B4b867CFda001101c617eCd347095B44 +// turnstile ID: 22 + +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.10; + +interface ITurnstile { + function assign(uint256) external returns (uint256); + + function register(address) external returns (uint256); +} diff --git a/contracts/manifold/FallbackRegistry.sol b/contracts/manifold/FallbackRegistry.sol deleted file mode 100644 index 3a63ddd6..00000000 --- a/contracts/manifold/FallbackRegistry.sol +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; - -import {Recipient} from "./overrides/IRoyaltySplitter.sol"; -import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol"; -import {IFallbackRegistry} from "./overrides/IFallbackRegistry.sol"; - -contract FallbackRegistry is IFallbackRegistry, Ownable2Step { - struct TokenFallback { - address tokenAddress; - Recipient[] recipients; - } - - mapping(address => Recipient[]) fallbacks; - - constructor(address initialOwner) { - _transferOwnership(initialOwner); - } - - function setFallback(address tokenAddress, Recipient[] calldata _recipients) public onlyOwner { - Recipient[] storage recipients = fallbacks[tokenAddress]; - uint256 recipientsLength = _recipients.length; - ///@solidity memory-safe-assembly - assembly { - // overwrite length directly rather than deleting and then updating it each time we push new values - // this means if the new array is shorter than the old ones, those slots will stay dirty, but they - // should not be able to be accessed due to the new length - sstore(recipients.slot, recipientsLength) - } - for (uint256 i; i < recipientsLength; ) { - recipients[i] = _recipients[i]; - unchecked { - ++i; - } - } - } - - function setFallbacks(TokenFallback[] calldata bundle) external onlyOwner { - uint256 bundleLength = bundle.length; - for (uint256 i = 0; i < bundleLength; ) { - TokenFallback calldata tokenFallback = bundle[i]; - setFallback(tokenFallback.tokenAddress, tokenFallback.recipients); - unchecked { - ++i; - } - } - } - - function getRecipients(address tokenAddress) external view returns (Recipient[] memory) { - return fallbacks[tokenAddress]; - } -} diff --git a/contracts/manifold/IRoyaltyRegistry.sol b/contracts/manifold/IRoyaltyRegistry.sol index 5c04200b..025b433c 100644 --- a/contracts/manifold/IRoyaltyRegistry.sol +++ b/contracts/manifold/IRoyaltyRegistry.sol @@ -19,7 +19,7 @@ interface IRoyaltyRegistry is IERC165 { * @param tokenAddress - The token address you wish to override * @param royaltyAddress - The royalty override address */ - function setRoyaltyLookupAddress(address tokenAddress, address royaltyAddress) external returns (bool); + function setRoyaltyLookupAddress(address tokenAddress, address royaltyAddress) external; /** * Returns royalty address location. Returns the tokenAddress by default, or the override if it exists @@ -28,14 +28,6 @@ interface IRoyaltyRegistry is IERC165 { */ function getRoyaltyLookupAddress(address tokenAddress) external view returns (address); - /** - * Returns the token address that an overrideAddress is set for. - * Note: will not be accurate if the override was created before this function was added. - * - * @param overrideAddress - The override address you are looking up the token for - */ - function getOverrideLookupTokenAddress(address overrideAddress) external view returns (address); - /** * Whether or not the message sender can override the royalty address for the given token address * diff --git a/contracts/manifold/RoyaltyEngineV1.sol b/contracts/manifold/RoyaltyEngineV1.sol index 00893ca6..ab4af32c 100644 --- a/contracts/manifold/RoyaltyEngineV1.sol +++ b/contracts/manifold/RoyaltyEngineV1.sol @@ -4,30 +4,26 @@ pragma solidity ^0.8.0; /// @author: manifold.xyz -import {ERC165, IERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; -import {ERC165Checker} from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; -import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; -import {AddressUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; - -import {SuperRareContracts} from "./libraries/SuperRareContracts.sol"; - -import {IManifold} from "./specs/IManifold.sol"; -import {IRaribleV1, IRaribleV2} from "./specs/IRarible.sol"; -import {IFoundation} from "./specs/IFoundation.sol"; -import {ISuperRareRegistry} from "./specs/ISuperRare.sol"; -import {IEIP2981} from "./specs/IEIP2981.sol"; -import {IZoraOverride} from "./specs/IZoraOverride.sol"; -import {IArtBlocksOverride} from "./specs/IArtBlocksOverride.sol"; -import {IKODAV2Override} from "./specs/IKODAV2Override.sol"; -import {IRoyaltyEngineV1} from "./IRoyaltyEngineV1.sol"; -import {IRoyaltyRegistry} from "./IRoyaltyRegistry.sol"; -import {IRoyaltySplitter, Recipient} from "./overrides/IRoyaltySplitter.sol"; -import {IFallbackRegistry} from "./overrides/IFallbackRegistry.sol"; +import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; +import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; + +import "./libraries/SuperRareContracts.sol"; + +import "./specs/IManifold.sol"; +import "./specs/IRarible.sol"; +import "./specs/IFoundation.sol"; +import "./specs/ISuperRare.sol"; +import "./specs/IEIP2981.sol"; +import "./specs/IZoraOverride.sol"; +import "./specs/IArtBlocksOverride.sol"; +import "./IRoyaltyEngineV1.sol"; +import "./IRoyaltyRegistry.sol"; /** * @dev Engine to lookup royalty configurations */ - contract RoyaltyEngineV1 is ERC165, OwnableUpgradeable, IRoyaltyEngineV1 { using AddressUpgradeable for address; @@ -36,29 +32,15 @@ contract RoyaltyEngineV1 is ERC165, OwnableUpgradeable, IRoyaltyEngineV1 { // Anything > NONE and <= NOT_CONFIGURED is considered not configured int16 private constant NONE = -1; int16 private constant NOT_CONFIGURED = 0; - int16 private constant MANIFOLD = 1; - int16 private constant RARIBLEV1 = 2; - int16 private constant RARIBLEV2 = 3; - int16 private constant FOUNDATION = 4; - int16 private constant EIP2981 = 5; - int16 private constant SUPERRARE = 6; - int16 private constant ZORA = 7; - int16 private constant ARTBLOCKS = 8; - int16 private constant KNOWNORIGINV2 = 9; - int16 private constant ROYALTY_SPLITTER = 10; - int16 private constant FALLBACK = type(int16).max; + int16 private constant EIP2981 = 1; + int16 private constant ZORA = 2; mapping(address => int16) _specCache; address public royaltyRegistry; - IFallbackRegistry public immutable FALLBACK_REGISTRY; - - constructor(address fallbackRegistry) { - FALLBACK_REGISTRY = IFallbackRegistry(fallbackRegistry); - } - function initialize(address _initialOwner, address royaltyRegistry_) public initializer { - _transferOwnership(_initialOwner); + function initialize(address royaltyRegistry_) public initializer { + __Ownable_init_unchained(); require(ERC165Checker.supportsInterface(royaltyRegistry_, type(IRoyaltyRegistry).interfaceId)); royaltyRegistry = royaltyRegistry_; } @@ -95,7 +77,7 @@ contract RoyaltyEngineV1 is ERC165, OwnableUpgradeable, IRoyaltyEngineV1 { uint256 value ) public override returns (address payable[] memory recipients, uint256[] memory amounts) { // External call to limit gas - try this._getRoyaltyAndSpec{gas: 100000}(tokenAddress, tokenId, value) returns ( + try this._getRoyaltyAndSpec{gas: 50000}(tokenAddress, tokenId, value) returns ( address payable[] memory _recipients, uint256[] memory _amounts, int16 spec, @@ -134,7 +116,7 @@ contract RoyaltyEngineV1 is ERC165, OwnableUpgradeable, IRoyaltyEngineV1 { /** * @dev Get the royalty and royalty spec for a given token * - * returns recipients array, amounts array, royalty spec, royalty address, whether or not to add to cache + * returns recipieints array, amounts array, royalty spec, royalty address, whether or not to add to cache */ function _getRoyaltyAndSpec( address tokenAddress, @@ -160,86 +142,15 @@ contract RoyaltyEngineV1 is ERC165, OwnableUpgradeable, IRoyaltyEngineV1 { // No spec configured yet, so we need to detect the spec addToCache = true; - // SuperRare handling - if (tokenAddress == SuperRareContracts.SUPERRARE_V1 || tokenAddress == SuperRareContracts.SUPERRARE_V2) { - try ISuperRareRegistry(SuperRareContracts.SUPERRARE_REGISTRY).tokenCreator(tokenAddress, tokenId) returns (address payable creator) { - try ISuperRareRegistry(SuperRareContracts.SUPERRARE_REGISTRY).calculateRoyaltyFee(tokenAddress, tokenId, value) returns ( - uint256 amount - ) { - recipients = new address payable[](1); - amounts = new uint256[](1); - recipients[0] = creator; - amounts[0] = amount; - return (recipients, amounts, SUPERRARE, royaltyAddress, addToCache); - } catch {} - } catch {} - } try IEIP2981(royaltyAddress).royaltyInfo(tokenId, value) returns (address recipient, uint256 amount) { - require(amount < value, "Invalid royalty amount"); - uint32 recipientSize; - assembly { - recipientSize := extcodesize(recipient) - } - if (recipientSize > 0) { - try IRoyaltySplitter(recipient).getRecipients() returns (Recipient[] memory splitRecipients) { - recipients = new address payable[](splitRecipients.length); - amounts = new uint256[](splitRecipients.length); - uint256 sum = 0; - uint256 splitRecipientsLength = splitRecipients.length; - for (uint256 i = 0; i < splitRecipientsLength; ) { - Recipient memory splitRecipient = splitRecipients[i]; - recipients[i] = payable(splitRecipient.recipient); - uint256 splitAmount = (splitRecipient.bps * amount) / 10000; - amounts[i] = splitAmount; - sum += splitAmount; - unchecked { - ++i; - } - } - // sum can be less than amount, otherwise small-value listings can break - require(sum <= amount, "Invalid split"); - - return (recipients, amounts, ROYALTY_SPLITTER, royaltyAddress, addToCache); - } catch {} - } // Supports EIP2981. Return amounts + require(amount < value, "Invalid royalty amount"); recipients = new address payable[](1); amounts = new uint256[](1); recipients[0] = payable(recipient); amounts[0] = amount; return (recipients, amounts, EIP2981, royaltyAddress, addToCache); } catch {} - try IManifold(royaltyAddress).getRoyalties(tokenId) returns (address payable[] memory recipients_, uint256[] memory bps) { - // Supports manifold interface. Compute amounts - require(recipients_.length == bps.length); - return (recipients_, _computeAmounts(value, bps), MANIFOLD, royaltyAddress, addToCache); - } catch {} - try IRaribleV2(royaltyAddress).getRaribleV2Royalties(tokenId) returns (IRaribleV2.Part[] memory royalties) { - // Supports rarible v2 interface. Compute amounts - recipients = new address payable[](royalties.length); - amounts = new uint256[](royalties.length); - uint256 totalAmount; - for (uint256 i = 0; i < royalties.length; i++) { - recipients[i] = royalties[i].account; - amounts[i] = (value * royalties[i].value) / 10000; - totalAmount += amounts[i]; - } - require(totalAmount < value, "Invalid royalty amount"); - return (recipients, amounts, RARIBLEV2, royaltyAddress, addToCache); - } catch {} - try IRaribleV1(royaltyAddress).getFeeRecipients(tokenId) returns (address payable[] memory recipients_) { - // Supports rarible v1 interface. Compute amounts - recipients_ = IRaribleV1(royaltyAddress).getFeeRecipients(tokenId); - try IRaribleV1(royaltyAddress).getFeeBps(tokenId) returns (uint256[] memory bps) { - require(recipients_.length == bps.length); - return (recipients_, _computeAmounts(value, bps), RARIBLEV1, royaltyAddress, addToCache); - } catch {} - } catch {} - try IFoundation(royaltyAddress).getFees(tokenId) returns (address payable[] memory recipients_, uint256[] memory bps) { - // Supports foundation interface. Compute amounts - require(recipients_.length == bps.length); - return (recipients_, _computeAmounts(value, bps), FOUNDATION, royaltyAddress, addToCache); - } catch {} try IZoraOverride(royaltyAddress).convertBidShares(tokenAddress, tokenId) returns ( address payable[] memory recipients_, uint256[] memory bps @@ -248,30 +159,6 @@ contract RoyaltyEngineV1 is ERC165, OwnableUpgradeable, IRoyaltyEngineV1 { require(recipients_.length == bps.length); return (recipients_, _computeAmounts(value, bps), ZORA, royaltyAddress, addToCache); } catch {} - try IArtBlocksOverride(royaltyAddress).getRoyalties(tokenAddress, tokenId) returns ( - address payable[] memory recipients_, - uint256[] memory bps - ) { - // Support Art Blocks override - require(recipients_.length == bps.length); - return (recipients_, _computeAmounts(value, bps), ARTBLOCKS, royaltyAddress, addToCache); - } catch {} - try IKODAV2Override(royaltyAddress).getKODAV2RoyaltyInfo(tokenAddress, tokenId, value) returns ( - address payable[] memory _recipients, - uint256[] memory _amounts - ) { - // Support KODA V2 override - require(_recipients.length == _amounts.length); - return (_recipients, _amounts, KNOWNORIGINV2, royaltyAddress, addToCache); - } catch {} - - try FALLBACK_REGISTRY.getRecipients(tokenAddress) returns (Recipient[] memory _recipients) { - uint256 recipientsLength = _recipients.length; - if (recipientsLength > 0) { - return _calculateFallback(_recipients, recipientsLength, value, royaltyAddress, addToCache); - } - } catch {} - // No supported royalties configured return (recipients, amounts, NONE, royaltyAddress, addToCache); } else { @@ -279,134 +166,23 @@ contract RoyaltyEngineV1 is ERC165, OwnableUpgradeable, IRoyaltyEngineV1 { addToCache = false; if (spec == NONE) { return (recipients, amounts, spec, royaltyAddress, addToCache); - } else if (spec == FALLBACK) { - Recipient[] memory _recipients = FALLBACK_REGISTRY.getRecipients(tokenAddress); - return _calculateFallback(_recipients, _recipients.length, value, royaltyAddress, addToCache); - } else if (spec == MANIFOLD) { - // Manifold spec - uint256[] memory bps; - (recipients, bps) = IManifold(royaltyAddress).getRoyalties(tokenId); - require(recipients.length == bps.length); - return (recipients, _computeAmounts(value, bps), spec, royaltyAddress, addToCache); - } else if (spec == RARIBLEV2) { - // Rarible v2 spec - IRaribleV2.Part[] memory royalties; - royalties = IRaribleV2(royaltyAddress).getRaribleV2Royalties(tokenId); - recipients = new address payable[](royalties.length); - amounts = new uint256[](royalties.length); - uint256 totalAmount; - for (uint256 i = 0; i < royalties.length; i++) { - recipients[i] = royalties[i].account; - amounts[i] = (value * royalties[i].value) / 10000; - totalAmount += amounts[i]; - } - require(totalAmount < value, "Invalid royalty amount"); - return (recipients, amounts, spec, royaltyAddress, addToCache); - } else if (spec == RARIBLEV1) { - // Rarible v1 spec - uint256[] memory bps; - recipients = IRaribleV1(royaltyAddress).getFeeRecipients(tokenId); - bps = IRaribleV1(royaltyAddress).getFeeBps(tokenId); - require(recipients.length == bps.length); - return (recipients, _computeAmounts(value, bps), spec, royaltyAddress, addToCache); - } else if (spec == FOUNDATION) { - // Foundation spec - uint256[] memory bps; - (recipients, bps) = IFoundation(royaltyAddress).getFees(tokenId); - require(recipients.length == bps.length); - return (recipients, _computeAmounts(value, bps), spec, royaltyAddress, addToCache); - } else if (spec == EIP2981 || spec == ROYALTY_SPLITTER) { + } else if (spec == EIP2981) { // EIP2981 spec (address recipient, uint256 amount) = IEIP2981(royaltyAddress).royaltyInfo(tokenId, value); require(amount < value, "Invalid royalty amount"); - if (spec == ROYALTY_SPLITTER) { - Recipient[] memory splitRecipients = IRoyaltySplitter(recipient).getRecipients(); - recipients = new address payable[](splitRecipients.length); - amounts = new uint256[](splitRecipients.length); - uint256 sum = 0; - uint256 splitRecipientsLength = splitRecipients.length; - for (uint256 i = 0; i < splitRecipientsLength; ) { - Recipient memory splitRecipient = splitRecipients[i]; - recipients[i] = payable(splitRecipient.recipient); - uint256 splitAmount = (splitRecipient.bps * amount) / 10000; - amounts[i] = splitAmount; - sum += splitAmount; - unchecked { - ++i; - } - } - // sum can be less than amount, otherwise small-value listings can break - require(sum <= value, "Invalid split"); - - return (recipients, amounts, spec, royaltyAddress, addToCache); - } recipients = new address payable[](1); amounts = new uint256[](1); recipients[0] = payable(recipient); amounts[0] = amount; return (recipients, amounts, spec, royaltyAddress, addToCache); - } else if (spec == SUPERRARE) { - // SUPERRARE spec - address payable creator = ISuperRareRegistry(SuperRareContracts.SUPERRARE_REGISTRY).tokenCreator(tokenAddress, tokenId); - uint256 amount = ISuperRareRegistry(SuperRareContracts.SUPERRARE_REGISTRY).calculateRoyaltyFee(tokenAddress, tokenId, value); - recipients = new address payable[](1); - amounts = new uint256[](1); - recipients[0] = creator; - amounts[0] = amount; - return (recipients, amounts, spec, royaltyAddress, addToCache); } else if (spec == ZORA) { // Zora spec uint256[] memory bps; (recipients, bps) = IZoraOverride(royaltyAddress).convertBidShares(tokenAddress, tokenId); require(recipients.length == bps.length); return (recipients, _computeAmounts(value, bps), spec, royaltyAddress, addToCache); - } else if (spec == ARTBLOCKS) { - // Art Blocks spec - uint256[] memory bps; - (recipients, bps) = IArtBlocksOverride(royaltyAddress).getRoyalties(tokenAddress, tokenId); - require(recipients.length == bps.length); - return (recipients, _computeAmounts(value, bps), spec, royaltyAddress, addToCache); - } else if (spec == KNOWNORIGINV2) { - // KnownOrigin.io V2 spec (V3 falls under EIP2981) - (recipients, amounts) = IKODAV2Override(royaltyAddress).getKODAV2RoyaltyInfo(tokenAddress, tokenId, value); - require(recipients.length == amounts.length); - return (recipients, amounts, spec, royaltyAddress, addToCache); - } - } - } - - function _calculateFallback( - Recipient[] memory _recipients, - uint256 recipientsLength, - uint256 value, - address royaltyAddress, - bool addToCache - ) - internal - pure - returns ( - address payable[] memory recipients, - uint256[] memory amounts, - int16 spec, - address _royaltyAddress, - bool _addToCache - ) - { - recipients = new address payable[](recipientsLength); - amounts = new uint256[](recipientsLength); - uint256 totalAmount; - for (uint256 i = 0; i < recipientsLength; ) { - Recipient memory recipient = _recipients[i]; - recipients[i] = payable(recipient.recipient); - uint256 amount = (value * recipient.bps) / 10_000; - amounts[i] = amount; - totalAmount += amount; - unchecked { - ++i; } } - require(totalAmount < value, "Invalid royalty amount"); - return (recipients, amounts, FALLBACK, royaltyAddress, addToCache); } /** diff --git a/contracts/manifold/RoyaltyRegistry.sol b/contracts/manifold/RoyaltyRegistry.sol index c12a21fc..e23bfdb0 100644 --- a/contracts/manifold/RoyaltyRegistry.sol +++ b/contracts/manifold/RoyaltyRegistry.sol @@ -23,22 +23,11 @@ import "./specs/IArtBlocks.sol"; contract RoyaltyRegistry is ERC165, OwnableUpgradeable, IRoyaltyRegistry { using AddressUpgradeable for address; - address public immutable OVERRIDE_FACTORY; - - /** - * @notice Constructor arg allows efficient lookup of override factory for single-tx overrides. - * However, this means the RoyaltyRegistry will need to be upgraded if the override factory is changed. - */ - constructor(address overrideFactory) { - OVERRIDE_FACTORY = overrideFactory; - } - // Override addresses mapping(address => address) private _overrides; - mapping(address => address) private _overrideLookupToTokenContract; - function initialize(address _initialOwner) public initializer { - _transferOwnership(_initialOwner); + function initialize() public initializer { + __Ownable_init_unchained(); } /** @@ -53,37 +42,18 @@ contract RoyaltyRegistry is ERC165, OwnableUpgradeable, IRoyaltyRegistry { */ function getRoyaltyLookupAddress(address tokenAddress) external view override returns (address) { address override_ = _overrides[tokenAddress]; - if (override_ != address(0)) { - return override_; - } + if (override_ != address(0)) return override_; return tokenAddress; } - /** - * @dev See {IRegistry-getOverrideTokenAddress}. - */ - function getOverrideLookupTokenAddress(address overrideAddress) external view override returns (address) { - return _overrideLookupToTokenContract[overrideAddress]; - } - /** * @dev See {IRegistry-setRoyaltyLookupAddress}. */ - function setRoyaltyLookupAddress(address tokenAddress, address royaltyLookupAddress) public override returns (bool) { + function setRoyaltyLookupAddress(address tokenAddress, address royaltyLookupAddress) public override { require(tokenAddress.isContract() && (royaltyLookupAddress.isContract() || royaltyLookupAddress == address(0)), "Invalid input"); require(overrideAllowed(tokenAddress), "Permission denied"); - // look up existing override, if any - address existingOverride = _overrides[tokenAddress]; - if (existingOverride != address(0)) { - // delete existing override reverse-lookup - _overrideLookupToTokenContract[existingOverride] = address(0); - } - _overrideLookupToTokenContract[royaltyLookupAddress] = tokenAddress; - // set new override and reverse-lookup _overrides[tokenAddress] = royaltyLookupAddress; - emit RoyaltyOverride(_msgSender(), tokenAddress, royaltyLookupAddress); - return true; } /** @@ -98,12 +68,6 @@ contract RoyaltyRegistry is ERC165, OwnableUpgradeable, IRoyaltyRegistry { try OwnableUpgradeable(tokenAddress).owner() returns (address owner) { if (owner == _msgSender()) return true; - - if (owner.isContract()) { - try OwnableUpgradeable(owner).owner() returns (address passThroughOwner) { - if (passThroughOwner == _msgSender()) return true; - } catch {} - } } catch {} try IAccessControlUpgradeable(tokenAddress).hasRole(0x00, _msgSender()) returns (bool hasRole) { @@ -147,19 +111,4 @@ contract RoyaltyRegistry is ERC165, OwnableUpgradeable, IRoyaltyRegistry { return false; } - - function _msgSender() internal view virtual override(ContextUpgradeable) returns (address) { - if (msg.sender == OVERRIDE_FACTORY) { - address relayedSender; - ///@solidity memory-safe-assembly - assembly { - // the factory appends the original msg.sender as last the word of calldata, which we can read using - // calldataload - relayedSender := calldataload(sub(calldatasize(), 0x20)) - } - return relayedSender; - } - // otherwise return msg.sender as normal - return msg.sender; - } } diff --git a/contracts/manifold/overrides/IFallbackRegistry.sol b/contracts/manifold/overrides/IFallbackRegistry.sol deleted file mode 100644 index dda6e88b..00000000 --- a/contracts/manifold/overrides/IFallbackRegistry.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; - -import {Recipient} from "./IRoyaltySplitter.sol"; - -interface IFallbackRegistry { - /** - * @dev Get total recipients for token fees. Note that recipient bps is of gross amount, not share of fee amount, - * ie, recipients' BPS will not sum to 10_000, but to the total fee BPS for an order. - */ - function getRecipients(address tokenAddress) external view returns (Recipient[] memory); -} diff --git a/contracts/manifold/overrides/IMultiReceiverRoyaltyOverride.sol b/contracts/manifold/overrides/IMultiReceiverRoyaltyOverride.sol deleted file mode 100644 index 7a22725b..00000000 --- a/contracts/manifold/overrides/IMultiReceiverRoyaltyOverride.sol +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -/// @author: manifold.xyz - -import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; -import "./IRoyaltySplitter.sol"; - -/** - * Multi-receiver EIP2981 reference override implementation - */ -interface IEIP2981MultiReceiverRoyaltyOverride is IERC165 { - event TokenRoyaltyRemoved(uint256 tokenId); - event TokenRoyaltySet(uint256 tokenId, uint16 royaltyBPS, Recipient[] recipients); - event DefaultRoyaltySet(uint16 royaltyBPS, Recipient[] recipients); - - struct TokenRoyaltyConfig { - uint256 tokenId; - uint16 royaltyBPS; - Recipient[] recipients; - } - - /** - * @dev Set per token royalties. Passing a recipient of address(0) will delete any existing configuration - */ - function setTokenRoyalties(TokenRoyaltyConfig[] calldata royalties) external; - - /** - * @dev Get all token royalty configurations - */ - function getTokenRoyalties() external view returns (TokenRoyaltyConfig[] memory); - - /** - * @dev Get the default royalty - */ - function getDefaultRoyalty() external view returns (uint16 bps, Recipient[] memory); - - /** - * @dev Set a default royalty configuration. Will be used if no token specific configuration is set - */ - function setDefaultRoyalty(uint16 bps, Recipient[] calldata recipients) external; - - /** - * @dev Helper function to get all splits contracts - */ - function getAllSplits() external view returns (address payable[] memory); -} diff --git a/contracts/manifold/overrides/IRoyaltySplitter.sol b/contracts/manifold/overrides/IRoyaltySplitter.sol deleted file mode 100644 index 97860038..00000000 --- a/contracts/manifold/overrides/IRoyaltySplitter.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -/// @author: manifold.xyz - -import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; - -struct Recipient { - address payable recipient; - uint16 bps; -} - -interface IRoyaltySplitter is IERC165 { - /** - * @dev Set the splitter recipients. Total bps must total 10000. - */ - function setRecipients(Recipient[] calldata recipients) external; - - /** - * @dev Get the splitter recipients; - */ - function getRecipients() external view returns (Recipient[] memory); -} diff --git a/contracts/manifold/overrides/MultiReceiverRoyaltyOverrideCloneable.sol b/contracts/manifold/overrides/MultiReceiverRoyaltyOverrideCloneable.sol deleted file mode 100644 index ed1913e8..00000000 --- a/contracts/manifold/overrides/MultiReceiverRoyaltyOverrideCloneable.sol +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -/// @author: manifold.xyz - -import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; - -import "./MultiReceiverRoyaltyOverrideCore.sol"; -import "./IRoyaltySplitter.sol"; -import "../IRoyaltyRegistry.sol"; - -/** - * Simple EIP2981 reference override implementation - */ -contract EIP2981MultiReceiverRoyaltyOverrideCloneable is EIP2981MultiReceiverRoyaltyMultiReceiverOverrideCore, OwnableUpgradeable { - function initialize( - address payable royaltySplitterCloneable, - uint16 defaultBps, - Recipient[] memory defaultRecipients, - address initialOwner - ) public initializer { - _transferOwnership(initialOwner); - _royaltySplitterCloneable = royaltySplitterCloneable; - // Initialize with default royalties - _setDefaultRoyalty(defaultBps, defaultRecipients); - } - - /** - * @dev See {IEIP2981MultiReceiverRoyaltyOverride-setTokenRoyalties}. - */ - function setTokenRoyalties(TokenRoyaltyConfig[] calldata royaltyConfigs) external override onlyOwner { - _setTokenRoyalties(royaltyConfigs); - } - - /** - * @dev See {IEIP2981MultiReceiverRoyaltyOverride-setDefaultRoyalty}. - */ - function setDefaultRoyalty(uint16 bps, Recipient[] calldata recipients) external override onlyOwner { - _setDefaultRoyalty(bps, recipients); - } -} diff --git a/contracts/manifold/overrides/MultiReceiverRoyaltyOverrideCore.sol b/contracts/manifold/overrides/MultiReceiverRoyaltyOverrideCore.sol deleted file mode 100644 index 5ed04ab7..00000000 --- a/contracts/manifold/overrides/MultiReceiverRoyaltyOverrideCore.sol +++ /dev/null @@ -1,148 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -/// @author: manifold.xyz - -import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; -import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import "@openzeppelin/contracts/proxy/Clones.sol"; - -import "./IMultiReceiverRoyaltyOverride.sol"; -import "./RoyaltySplitter.sol"; -import "./IRoyaltySplitter.sol"; -import "../specs/IEIP2981.sol"; - -/** - * Multi-receiver EIP2981 reference override implementation - */ -abstract contract EIP2981MultiReceiverRoyaltyMultiReceiverOverrideCore is IEIP2981, IEIP2981MultiReceiverRoyaltyOverride, ERC165 { - uint16 private _defaultRoyaltyBPS; - address payable private _defaultRoyaltySplitter; - - mapping(uint256 => address payable) private _tokenRoyaltiesSplitter; - mapping(uint256 => uint16) private _tokenRoyaltiesBPS; - uint256[] private _tokensWithRoyalties; - - // Address of cloneable splitter contract - address internal _royaltySplitterCloneable; - - function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { - return - interfaceId == type(IEIP2981).interfaceId || - interfaceId == type(IEIP2981MultiReceiverRoyaltyOverride).interfaceId || - super.supportsInterface(interfaceId); - } - - /** - * @dev Sets token royalties. When you override this in the implementation contract - * ensure that you access restrict it to the contract owner or admin - */ - function _setTokenRoyalties(TokenRoyaltyConfig[] memory royaltyConfigs) internal { - for (uint256 i; i < royaltyConfigs.length; i++) { - TokenRoyaltyConfig memory royaltyConfig = royaltyConfigs[i]; - require(royaltyConfig.royaltyBPS < 10000, "Invalid bps"); - Recipient[] memory recipients = royaltyConfig.recipients; - address payable splitterAddress = _tokenRoyaltiesSplitter[royaltyConfig.tokenId]; - if (recipients.length == 0) { - if (splitterAddress != address(0)) { - IRoyaltySplitter(splitterAddress).setRecipients(recipients); - } - delete _tokenRoyaltiesBPS[royaltyConfig.tokenId]; - emit TokenRoyaltyRemoved(royaltyConfig.tokenId); - } else { - if (splitterAddress == address(0)) { - splitterAddress = payable(Clones.clone(_royaltySplitterCloneable)); - RoyaltySplitter(splitterAddress).initialize(recipients); - _tokenRoyaltiesSplitter[royaltyConfig.tokenId] = splitterAddress; - _tokensWithRoyalties.push(royaltyConfig.tokenId); - } else { - IRoyaltySplitter(splitterAddress).setRecipients(recipients); - } - _tokenRoyaltiesBPS[royaltyConfig.tokenId] = royaltyConfig.royaltyBPS; - emit TokenRoyaltySet(royaltyConfig.tokenId, royaltyConfig.royaltyBPS, recipients); - } - } - } - - /** - * @dev Sets default royalty. When you override this in the implementation contract - * ensure that you access restrict it to the contract owner or admin - */ - function _setDefaultRoyalty(uint16 bps, Recipient[] memory recipients) internal { - require(bps < 10000, "Invalid bps"); - if (_defaultRoyaltySplitter == address(0)) { - _defaultRoyaltySplitter = payable(Clones.clone(_royaltySplitterCloneable)); - RoyaltySplitter(_defaultRoyaltySplitter).initialize(recipients); - } else { - IRoyaltySplitter(_defaultRoyaltySplitter).setRecipients(recipients); - } - _defaultRoyaltyBPS = bps; - emit DefaultRoyaltySet(bps, recipients); - } - - /** - * @dev See {IEIP2981MultiReceiverRoyaltyOverride-getTokenRoyalties}. - */ - function getTokenRoyalties() external view override returns (TokenRoyaltyConfig[] memory royaltyConfigs) { - royaltyConfigs = new TokenRoyaltyConfig[](_tokensWithRoyalties.length); - for (uint256 i; i < _tokensWithRoyalties.length; ++i) { - TokenRoyaltyConfig memory royaltyConfig; - uint256 tokenId = _tokensWithRoyalties[i]; - address splitterAddress = _tokenRoyaltiesSplitter[tokenId]; - if (splitterAddress != address(0)) { - royaltyConfig.recipients = IRoyaltySplitter(splitterAddress).getRecipients(); - } - royaltyConfig.tokenId = tokenId; - royaltyConfig.royaltyBPS = _tokenRoyaltiesBPS[tokenId]; - royaltyConfigs[i] = royaltyConfig; - } - } - - /** - * @dev See {IEIP2981MultiReceiverRoyaltyOverride-getDefaultRoyalty}. - */ - function getDefaultRoyalty() external view override returns (uint16 bps, Recipient[] memory recipients) { - if (_defaultRoyaltySplitter != address(0)) { - recipients = IRoyaltySplitter(_defaultRoyaltySplitter).getRecipients(); - } - return (_defaultRoyaltyBPS, recipients); - } - - /** - * @dev See {IEIP2981MultiReceiverRoyaltyOverride-royaltyInfo}. - */ - function royaltyInfo(uint256 tokenId, uint256 value) public view override returns (address, uint256) { - if (_tokenRoyaltiesSplitter[tokenId] != address(0)) { - return (_tokenRoyaltiesSplitter[tokenId], (value * _tokenRoyaltiesBPS[tokenId]) / 10000); - } - if (_defaultRoyaltySplitter != address(0) && _defaultRoyaltyBPS != 0) { - return (_defaultRoyaltySplitter, (value * _defaultRoyaltyBPS) / 10000); - } - return (address(0), 0); - } - - /** - * @dev See {IEIP2981MultiReceiverRoyaltyOverride-getAllSplits}. - */ - function getAllSplits() external view override returns (address payable[] memory splits) { - uint256 startingIndex; - uint256 endingIndex = _tokensWithRoyalties.length; - if (_defaultRoyaltySplitter != address(0)) { - splits = new address payable[](1 + _tokensWithRoyalties.length); - splits[0] = _defaultRoyaltySplitter; - startingIndex = 1; - ++endingIndex; - } else { - // unreachable in practice - splits = new address payable[](_tokensWithRoyalties.length); - } - for (uint256 i = startingIndex; i < endingIndex; ++i) { - splits[i] = _tokenRoyaltiesSplitter[_tokensWithRoyalties[i - startingIndex]]; - } - } - - function getRecipients() public view returns (Recipient[] memory) { - return RoyaltySplitter(_defaultRoyaltySplitter).getRecipients(); - } -} diff --git a/contracts/manifold/overrides/RoyaltyOverrideCloneable.sol b/contracts/manifold/overrides/RoyaltyOverrideCloneable.sol index 34daa243..aab41b6d 100644 --- a/contracts/manifold/overrides/RoyaltyOverrideCloneable.sol +++ b/contracts/manifold/overrides/RoyaltyOverrideCloneable.sol @@ -12,9 +12,8 @@ import "./RoyaltyOverrideCore.sol"; * Simple EIP2981 reference override implementation */ contract EIP2981RoyaltyOverrideCloneable is EIP2981RoyaltyOverrideCore, OwnableUpgradeable { - function initialize(TokenRoyalty calldata _defaultRoyalty, address initialOwner) public initializer { - _transferOwnership(initialOwner); - _setDefaultRoyalty(_defaultRoyalty); + function initialize() public initializer { + __Ownable_init(); } /** diff --git a/contracts/manifold/overrides/RoyaltyOverrideFactory.sol b/contracts/manifold/overrides/RoyaltyOverrideFactory.sol deleted file mode 100644 index eae1aaac..00000000 --- a/contracts/manifold/overrides/RoyaltyOverrideFactory.sol +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -/// @author: manifold.xyz - -import "@openzeppelin/contracts/proxy/Clones.sol"; -import {EIP2981RoyaltyOverrideCloneable} from "./RoyaltyOverrideCloneable.sol"; -import {EIP2981MultiReceiverRoyaltyOverrideCloneable} from "./MultiReceiverRoyaltyOverrideCloneable.sol"; -import {IRoyaltyRegistry} from "../IRoyaltyRegistry.sol"; -import {Recipient} from "./IRoyaltySplitter.sol"; - -/** - * Clone Factory for EIP2981 reference override implementation - */ -contract EIP2981RoyaltyOverrideFactory { - address public immutable SINGLE_RECIPIENT_ORIGIN_ADDRESS; - address public immutable MULTI_RECIPIENT_ORIGIN_ADDRESS; - address payable public immutable ROYALTY_SPLITTER_ORIGIN_ADDRESS; - - error InvalidRoyaltyRegistryAddress(); - - uint256 constant INVALID_ROYALTY_REGISTRY_ADDRESS_SELECTOR = 0x1c491d3; - - event EIP2981RoyaltyOverrideCreated(address newEIP2981RoyaltyOverride); - - constructor( - address singleOrigin, - address multiOrigin, - address payable royaltySplitterOrigin - ) { - SINGLE_RECIPIENT_ORIGIN_ADDRESS = singleOrigin; - MULTI_RECIPIENT_ORIGIN_ADDRESS = multiOrigin; - ROYALTY_SPLITTER_ORIGIN_ADDRESS = royaltySplitterOrigin; - } - - function createOverrideAndRegister( - address royaltyRegistry, - address tokenAddress, - EIP2981RoyaltyOverrideCloneable.TokenRoyalty calldata defaultRoyalty - ) public returns (address) { - address clone = Clones.clone(SINGLE_RECIPIENT_ORIGIN_ADDRESS); - EIP2981RoyaltyOverrideCloneable(clone).initialize(defaultRoyalty, msg.sender); - emit EIP2981RoyaltyOverrideCreated(clone); - registerOverride(royaltyRegistry, tokenAddress, clone); - return clone; - } - - function createOverrideAndRegister( - address royaltyRegistry, - address tokenAddress, - uint16 defaultBps, - Recipient[] calldata defaultRecipients - ) public returns (address) { - address clone = Clones.clone(MULTI_RECIPIENT_ORIGIN_ADDRESS); - EIP2981MultiReceiverRoyaltyOverrideCloneable(clone).initialize(ROYALTY_SPLITTER_ORIGIN_ADDRESS, defaultBps, defaultRecipients, msg.sender); - emit EIP2981RoyaltyOverrideCreated(clone); - registerOverride(royaltyRegistry, tokenAddress, clone); - return clone; - } - - function registerOverride( - address royaltyRegistry, - address tokenAddress, - address lookupAddress - ) internal { - // encode setRoyaltyLookupAddress call with tokenAddress and lookupAddress and also append msg.sender to calldata. - // Including the original msg.sender allows the registry to securely verify the caller is the owner of the token - bytes memory data = abi.encodeWithSelector(IRoyaltyRegistry.setRoyaltyLookupAddress.selector, tokenAddress, lookupAddress, msg.sender); - - // check success and return data, and bubble up original revert reason if call was unsuccessful - ///@solidity memory-safe-assembly - assembly { - // clear first word of scratch space, where we will store one word of returndata - // if the call results in no returndata is available, this would not be overwritten otherwise - mstore(0, 0) - let success := call(gas(), royaltyRegistry, 0, add(data, 0x20), mload(data), 0, 0x20) - - // check if call succeeded - if iszero(success) { - // copy all of returndata to memory starting at 0; we don't have to worry about dirtying memory since - // we are reverting. - returndatacopy(0, 0, returndatasize()) - revert(0, returndatasize()) - } - // check if returned boolean is true, since a successful call does not guarantee a successful execution - let returned := mload(0) - if iszero(eq(returned, 1)) { - mstore(0, INVALID_ROYALTY_REGISTRY_ADDRESS_SELECTOR) - revert(0x1c, 4) - } - } - } -} diff --git a/contracts/manifold/overrides/RoyaltySplitter.sol b/contracts/manifold/overrides/RoyaltySplitter.sol deleted file mode 100644 index 07c7f010..00000000 --- a/contracts/manifold/overrides/RoyaltySplitter.sol +++ /dev/null @@ -1,194 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 - -pragma solidity ^0.8.0; - -import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; -import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; -import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; -import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; -import "@openzeppelin/contracts/utils/math/SafeMath.sol"; -import "@openzeppelin/contracts/proxy/Clones.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "../libraries/BytesLibrary.sol"; -import "./IRoyaltySplitter.sol"; - -interface IERC20Approve { - function approve(address spender, uint256 amount) external returns (bool); - - function increaseAllowance(address spender, uint256 amount) external returns (bool); -} - -/** - * Cloneable and configurable royalty splitter contract - */ -contract RoyaltySplitter is Initializable, OwnableUpgradeable, IRoyaltySplitter, ERC165 { - using BytesLibrary for bytes; - using AddressUpgradeable for address payable; - using AddressUpgradeable for address; - using SafeMath for uint256; - - uint256 internal constant BASIS_POINTS = 10000; - uint256 constant IERC20_APPROVE_SELECTOR = 0x095ea7b300000000000000000000000000000000000000000000000000000000; - uint256 constant SELECTOR_MASK = 0xffffffff00000000000000000000000000000000000000000000000000000000; - - Recipient[] private _recipients; - - event PercentSplitCreated(address indexed contractAddress); - event PercentSplitShare(address indexed recipient, uint256 percentInBasisPoints); - event ETHTransferred(address indexed account, uint256 amount); - event ERC20Transferred(address indexed erc20Contract, address indexed account, uint256 amount); - - function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { - return interfaceId == type(IRoyaltySplitter).interfaceId || super.supportsInterface(interfaceId); - } - - /** - * @dev Requires that the msg.sender is one of the recipients in this split. - */ - modifier onlyRecipient() { - for (uint256 i = 0; i < _recipients.length; i++) { - if (_recipients[i].recipient == msg.sender) { - _; - return; - } - } - revert("Split: Can only be called by one of the recipients"); - } - - /** - * @notice Called once to configure the contract after the initial deployment. - * @dev This will be called by `createSplit` after deploying the proxy so it should never be called directly. - */ - function initialize(Recipient[] calldata recipients) public initializer { - __Ownable_init(); - _setRecipients(recipients); - } - - /** - * @dev Set the splitter recipients. Total bps must total 10000. - */ - function setRecipients(Recipient[] calldata recipients) external override onlyOwner { - _setRecipients(recipients); - } - - function _setRecipients(Recipient[] calldata recipients) private { - delete _recipients; - if (recipients.length == 0) { - return; - } - uint256 totalBPS; - for (uint256 i; i < recipients.length; ++i) { - totalBPS += recipients[i].bps; - _recipients.push(recipients[i]); - } - require(totalBPS == BASIS_POINTS, "Total bps must be 10000"); - } - - /** - * @dev Get the splitter recipients; - */ - function getRecipients() external view override returns (Recipient[] memory) { - return _recipients; - } - - /** - * @notice Forwards any ETH received to the recipients in this split. - * @dev Each recipient increases the gas required to split - * and contract recipients may significantly increase the gas required. - */ - receive() external payable { - _splitETH(msg.value); - } - - /** - * @notice Allows any ETH stored by the contract to be split among recipients. - * @dev Normally ETH is forwarded as it comes in, but a balance in this contract - * is possible if it was sent before the contract was created or if self destruct was used. - */ - function splitETH() public { - _splitETH(address(this).balance); - } - - function _splitETH(uint256 value) internal { - if (value > 0) { - uint256 totalSent; - uint256 amountToSend; - unchecked { - for (uint256 i = _recipients.length - 1; i > 0; i--) { - Recipient memory recipient = _recipients[i]; - amountToSend = (value * recipient.bps) / BASIS_POINTS; - totalSent += amountToSend; - recipient.recipient.sendValue(amountToSend); - emit ETHTransferred(recipient.recipient, amountToSend); - } - // Favor the 1st recipient if there are any rounding issues - amountToSend = value - totalSent; - } - _recipients[0].recipient.sendValue(amountToSend); - emit ETHTransferred(_recipients[0].recipient, amountToSend); - } - } - - /** - * @notice Anyone can call this function to split all available tokens at the provided address between the recipients. - * @dev This contract is built to split ETH payments. The ability to attempt to split ERC20 tokens is here - * just in case tokens were also sent so that they don't get locked forever in the contract. - */ - function splitERC20Tokens(IERC20 erc20Contract) public { - require(_splitERC20Tokens(erc20Contract), "Split: ERC20 split failed"); - } - - function _splitERC20Tokens(IERC20 erc20Contract) internal returns (bool) { - try erc20Contract.balanceOf(address(this)) returns (uint256 balance) { - if (balance == 0) { - return false; - } - uint256 amountToSend; - uint256 totalSent; - unchecked { - for (uint256 i = _recipients.length - 1; i > 0; i--) { - Recipient memory recipient = _recipients[i]; - bool success; - (success, amountToSend) = balance.tryMul(recipient.bps); - - amountToSend /= BASIS_POINTS; - totalSent += amountToSend; - try erc20Contract.transfer(recipient.recipient, amountToSend) { - emit ERC20Transferred(address(erc20Contract), recipient.recipient, amountToSend); - } catch { - return false; - } - } - // Favor the 1st recipient if there are any rounding issues - amountToSend = balance - totalSent; - } - try erc20Contract.transfer(_recipients[0].recipient, amountToSend) { - emit ERC20Transferred(address(erc20Contract), _recipients[0].recipient, amountToSend); - } catch { - return false; - } - return true; - } catch { - return false; - } - } - - /** - * @notice Allows the split recipients to make an arbitrary contract call. - * @dev This is provided to allow recovering from unexpected scenarios, - * such as receiving an NFT at this address. - * - * It will first attempt a fair split of ERC20 tokens before proceeding. - * - * This contract is built to split ETH payments. The ability to attempt to make other calls is here - * just in case other assets were also sent so that they don't get locked forever in the contract. - */ - function proxyCall(address payable target, bytes calldata callData) external onlyRecipient { - require( - !callData.startsWith(IERC20Approve.approve.selector) && !callData.startsWith(IERC20Approve.increaseAllowance.selector), - "Split: ERC20 tokens must be split" - ); - try this.splitERC20Tokens(IERC20(target)) {} catch {} - target.functionCall(callData); - } -} diff --git a/contracts/modules/Asks/Core/ERC20/AsksCoreErc20.sol b/contracts/modules/Asks/Core/ERC20/AsksCoreErc20.sol deleted file mode 100644 index d0dcef6a..00000000 --- a/contracts/modules/Asks/Core/ERC20/AsksCoreErc20.sol +++ /dev/null @@ -1,372 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {ReentrancyGuard} from "@rari-capital/solmate/src/utils/ReentrancyGuard.sol"; -import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; - -import {ERC721TransferHelper} from "../../../../transferHelpers/ERC721TransferHelper.sol"; -import {IncomingTransferSupportV1} from "../../../../common/IncomingTransferSupport/V1/IncomingTransferSupportV1.sol"; -import {FeePayoutSupportV1} from "../../../../common/FeePayoutSupport/FeePayoutSupportV1.sol"; -import {ModuleNamingSupportV1} from "../../../../common/ModuleNamingSupport/ModuleNamingSupportV1.sol"; -import {IAsksCoreErc20} from "./IAsksCoreErc20.sol"; - -/// @title Asks Core ERC-20 -/// @author kulkarohan -/// @notice Module for minimal ERC-20 asks for ERC-721 tokens -contract AsksCoreErc20 is ReentrancyGuard, IncomingTransferSupportV1, FeePayoutSupportV1, ModuleNamingSupportV1 { - /// /// - /// IMMUTABLES /// - /// /// - - /// @notice The ZORA ERC-721 Transfer Helper - ERC721TransferHelper public immutable erc721TransferHelper; - - /// @param _erc20TransferHelper The ZORA ERC-20 Transfer Helper address - /// @param _erc721TransferHelper The ZORA ERC-721 Transfer Helper address - /// @param _royaltyEngine The Manifold Royalty Engine address - /// @param _protocolFeeSettings The ZORA Protocol Fee Settings address - /// @param _weth The WETH token address - constructor( - address _erc20TransferHelper, - address _erc721TransferHelper, - address _royaltyEngine, - address _protocolFeeSettings, - address _weth - ) - IncomingTransferSupportV1(_erc20TransferHelper) - FeePayoutSupportV1(_royaltyEngine, _protocolFeeSettings, _weth, ERC721TransferHelper(_erc721TransferHelper).ZMM().registrar()) - ModuleNamingSupportV1("Asks Core ERC-20") - { - erc721TransferHelper = ERC721TransferHelper(_erc721TransferHelper); - } - - /// @notice Implements EIP-165 for standard interface detection - /// @dev `0x01ffc9a7` is the IERC165 interface id - /// @param _interfaceId The identifier of a given interface - /// @return If the given interface is supported - function supportsInterface(bytes4 _interfaceId) external pure returns (bool) { - return _interfaceId == type(IAsksCoreErc20).interfaceId || _interfaceId == 0x01ffc9a7; - } - - /// /// - /// ASK STORAGE /// - /// /// - - /// @notice The metadata for a given ask - /// @param seller The address of the seller - /// @param price The price to fill the ask - /// @param currency The address of the ERC-20 currency, or address(0) for ETH - struct Ask { - address seller; - uint96 price; - address currency; - } - - /// @notice The ask for a given NFT, if one exists - /// @dev ERC-721 token contract => ERC-721 token id => Ask - mapping(address => mapping(uint256 => Ask)) public askForNFT; - - /// /// - /// CREATE ASK /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,-------------. - // / \ |AsksCoreErc20| - // Caller `------+------' - // | createAsk() | - // | ------------------->| - // | | - // | ----. - // | | store ask metadata - // | <---' - // | | - // | ----. - // | | emit AskCreated() - // | <---' - // Caller ,------+------. - // ,-. |AsksCoreErc20| - // `-' `-------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an ask is created - /// @param tokenContract The ERC-721 token address of the created ask - /// @param tokenId The ERC-721 token id of the created ask - /// @param ask The metadata of the created ask - event AskCreated(address indexed tokenContract, uint256 indexed tokenId, Ask ask); - - /// @notice Creates an ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _price The price to fill the ask - /// @param _currency The currency of the ask price - function createAsk( - address _tokenContract, - uint256 _tokenId, - uint256 _price, - address _currency - ) external nonReentrant { - // Get the owner of the specified token - address tokenOwner = IERC721(_tokenContract).ownerOf(_tokenId); - - // Ensure the caller is the owner or an approved operator - require(msg.sender == tokenOwner || IERC721(_tokenContract).isApprovedForAll(tokenOwner, msg.sender), "ONLY_TOKEN_OWNER_OR_OPERATOR"); - - // Ensure the price can be downcasted to 96 bits for this module - // For a higher ask price, use the supporting module - require(_price <= type(uint96).max, "INVALID_ASK_PRICE"); - - // Store the ask metadata - askForNFT[_tokenContract][_tokenId].seller = tokenOwner; - askForNFT[_tokenContract][_tokenId].price = uint96(_price); - askForNFT[_tokenContract][_tokenId].currency = _currency; - - emit AskCreated(_tokenContract, _tokenId, askForNFT[_tokenContract][_tokenId]); - } - - /// /// - /// UPDATE ASK /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,-------------. - // / \ |AsksCoreErc20| - // Caller `------+------' - // | setAskPrice() | - // | ------------------->| - // | | - // | | - // | _______________________________________ - // | ! ALT / price change? ! - // | !_____/ | ! - // | ! ----. ! - // | ! | update price ! - // | ! <---' ! - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | !~[noop]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | | - // | | - // | __________________________________________ - // | ! ALT / currency change? ! - // | !_____/ | ! - // | ! ----. ! - // | ! | update currency ! - // | ! <---' ! - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | !~[noop]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | | - // | ----. - // | | emit AskPriceUpdated() - // | <---' - // Caller ,------+------. - // ,-. |AsksCoreErc20| - // `-' `-------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an ask price is updated - /// @param tokenContract The ERC-721 token address of the updated ask - /// @param tokenId The ERC-721 token id of the updated ask - /// @param ask The metadata of the updated the ask - event AskPriceUpdated(address indexed tokenContract, uint256 indexed tokenId, Ask ask); - - /// @notice Updates the ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _price The price to fill the ask - /// @param _currency The currency of the ask price - function setAskPrice( - address _tokenContract, - uint256 _tokenId, - uint256 _price, - address _currency - ) external nonReentrant { - // Get the ask for the specified token - Ask storage ask = askForNFT[_tokenContract][_tokenId]; - - // Ensure the caller is seller - require(msg.sender == ask.seller, "ONLY_SELLER"); - - // If updating the price, - if (_price != ask.price) { - // Ensure the price to set can be downcasted - require(_price <= type(uint96).max, "INVALID_ASK_PRICE"); - - // Store the new price - ask.price = uint96(_price); - } - - // If updating the currency, - if (_currency != ask.currency) { - // Store the new currency - ask.currency = _currency; - } - - emit AskPriceUpdated(_tokenContract, _tokenId, ask); - } - - /// /// - /// CANCEL ASK /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,-------------. - // / \ |AsksCoreErc20| - // Caller `------+------' - // | cancelAsk() | - // | ------------------->| - // | | - // | ----. - // | | emit AskCanceled() - // | <---' - // | | - // | ----. - // | | delete ask - // | <---' - // Caller ,------+------. - // ,-. |AsksCoreErc20| - // `-' `-------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an ask is canceled - /// @param tokenContract The ERC-721 token address of the canceled ask - /// @param tokenId The ERC-721 token id of the canceled ask - /// @param ask The metadata of the canceled ask - event AskCanceled(address indexed tokenContract, uint256 indexed tokenId, Ask ask); - - /// @notice Cancels the ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function cancelAsk(address _tokenContract, uint256 _tokenId) external nonReentrant { - // Get the ask for the specified token - Ask memory ask = askForNFT[_tokenContract][_tokenId]; - - // Ensure the caller is the seller or a new owner of the token - require(msg.sender == ask.seller || msg.sender == IERC721(_tokenContract).ownerOf(_tokenId), "ONLY_SELLER_OR_TOKEN_OWNER"); - - emit AskCanceled(_tokenContract, _tokenId, ask); - - // Remove the ask from storage - delete askForNFT[_tokenContract][_tokenId]; - } - - /// /// - /// FILL ASK /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,-------------. ,--------------------. - // / \ |AsksCoreErc20| |ERC721TransferHelper| - // Caller `------+------' `---------+----------' - // | fillAsk() | | - // | ------------------->| | - // | | | - // | ----. - // | | validate received payment - // | <---' - // | | | - // | ----. | - // | | handle royalty payouts | - // | <---' | - // | | | - // | ----. | - // | | handle seller payout | - // | <---' | - // | | | - // | | transferFrom() | - // | |-----------------------------> - // | | | - // | | |----. - // | | | | transfer NFT from seller to buyer - // | | |<---' - // | | | - // | ----. | - // | | emit AskFilled() | - // | <---' | - // | | | - // | ----. | - // | | delete ask from contract| - // | <---' | - // Caller ,------+------. ,---------+----------. - // ,-. |AsksCoreErc20| |ERC721TransferHelper| - // `-' `-------------' `--------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an ask is filled - /// @param tokenContract The ERC-721 token address of the filled ask - /// @param tokenId The ERC-721 token id of the filled ask - /// @param buyer The buyer address of the filled ask - /// @param ask The metadata of the filled ask - event AskFilled(address indexed tokenContract, uint256 indexed tokenId, address buyer, Ask ask); - - /// @notice Fills the ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _price The price to fill the ask - /// @param _currency The currency to fill the ask - function fillAsk( - address _tokenContract, - uint256 _tokenId, - uint256 _price, - address _currency - ) external payable nonReentrant { - // Get the ask for the specified token - Ask memory ask = askForNFT[_tokenContract][_tokenId]; - - // Cache the seller - address seller = ask.seller; - - // Ensure the ask is active - require(seller != address(0), "INACTIVE_ASK"); - - // Cache the price - uint256 price = ask.price; - - // Ensure the specified price matches the ask price - require(_price == price, "MUST_MATCH_PRICE"); - - // Cache the currency - address currency = ask.currency; - - // Ensure the specified currency matches the ask currency - require(_currency == currency, "MUST_MATCH_CURRENCY"); - - // Transfer the ask price from the buyer - // If ETH, this reverts if the buyer did not attach enough - // If ERC-20, this reverts if the buyer did not approve the ERC20TransferHelper or does not own the specified tokens - _handleIncomingTransfer(price, currency); - - // Payout associated token royalties, if any - (uint256 remainingProfit, ) = _handleRoyaltyPayout(_tokenContract, _tokenId, price, currency, 300000); - - // Payout the module fee, if configured - remainingProfit = _handleProtocolFeePayout(remainingProfit, currency); - - // Transfer the remaining profit to the seller - _handleOutgoingTransfer(seller, remainingProfit, currency, 50000); - - // Transfer the NFT to the buyer - // Reverts if the seller did not approve the ERC721TransferHelper or no longer owns the token - erc721TransferHelper.transferFrom(_tokenContract, seller, msg.sender, _tokenId); - - emit AskFilled(_tokenContract, _tokenId, msg.sender, ask); - - // Remove the ask from storage - delete askForNFT[_tokenContract][_tokenId]; - } -} diff --git a/contracts/modules/Asks/Core/ERC20/IAsksCoreErc20.sol b/contracts/modules/Asks/Core/ERC20/IAsksCoreErc20.sol deleted file mode 100644 index 471387da..00000000 --- a/contracts/modules/Asks/Core/ERC20/IAsksCoreErc20.sol +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -/// @title IAsksCoreErc20 -/// @author kulkarohan -/// @notice Interface for Asks Core ERC-20 -interface IAsksCoreErc20 { - /// @notice Creates an ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _price The price to fill the ask - /// @param _currency The currency of the ask price - function createAsk( - address _tokenContract, - uint256 _tokenId, - uint256 _price, - address _currency - ) external; - - /// @notice Updates the ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _price The price to fill the ask - /// @param _currency The currency of the ask price - function setAskPrice( - address _tokenContract, - uint256 _tokenId, - uint256 _price, - address _currency - ) external; - - /// @notice Cancels the ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function cancelAsk(address _tokenContract, uint256 _tokenId) external; - - /// @notice Fills the ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _price The price to fill the ask - /// @param _currency The currency to fill the ask - function fillAsk( - address _tokenContract, - uint256 _tokenId, - uint256 _price, - address _currency - ) external payable; -} diff --git a/contracts/modules/Asks/Core/ETH/AsksCoreEth.sol b/contracts/modules/Asks/Core/ETH/AsksCoreEth.sol deleted file mode 100644 index 2bc0c548..00000000 --- a/contracts/modules/Asks/Core/ETH/AsksCoreEth.sol +++ /dev/null @@ -1,322 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {ReentrancyGuard} from "@rari-capital/solmate/src/utils/ReentrancyGuard.sol"; -import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; - -import {ERC721TransferHelper} from "../../../../transferHelpers/ERC721TransferHelper.sol"; -import {FeePayoutSupportV1} from "../../../../common/FeePayoutSupport/FeePayoutSupportV1.sol"; -import {ModuleNamingSupportV1} from "../../../../common/ModuleNamingSupport/ModuleNamingSupportV1.sol"; -import {IAsksCoreEth} from "./IAsksCoreEth.sol"; - -/// @title Asks Core ETH -/// @author kulkarohan -/// @notice Module for minimal ETH asks for ERC-721 tokens -contract AsksCoreEth is ReentrancyGuard, FeePayoutSupportV1, ModuleNamingSupportV1 { - /// /// - /// IMMUTABLES /// - /// /// - - /// @notice The ZORA ERC-721 Transfer Helper - ERC721TransferHelper public immutable erc721TransferHelper; - - /// @param _erc721TransferHelper The ZORA ERC-721 Transfer Helper address - /// @param _royaltyEngine The Manifold Royalty Engine address - /// @param _protocolFeeSettings The ZORA Protocol Fee Settings address - /// @param _weth The WETH token address - constructor( - address _erc721TransferHelper, - address _royaltyEngine, - address _protocolFeeSettings, - address _weth - ) - FeePayoutSupportV1(_royaltyEngine, _protocolFeeSettings, _weth, ERC721TransferHelper(_erc721TransferHelper).ZMM().registrar()) - ModuleNamingSupportV1("Asks Core ETH") - { - erc721TransferHelper = ERC721TransferHelper(_erc721TransferHelper); - } - - /// @notice Implements EIP-165 for standard interface detection - /// @dev `0x01ffc9a7` is the IERC165 interface id - /// @param _interfaceId The identifier of a given interface - /// @return If the given interface is supported - function supportsInterface(bytes4 _interfaceId) external pure returns (bool) { - return _interfaceId == type(IAsksCoreEth).interfaceId || _interfaceId == 0x01ffc9a7; - } - - /// /// - /// ASK STORAGE /// - /// /// - - /// @notice The metadata for a given ask - /// @param seller The address of the seller - /// @param price The price to fill the ask - struct Ask { - address seller; - uint96 price; - } - - /// @notice The ask for a given NFT - /// @dev ERC-721 token contract => ERC-721 token id => Ask - mapping(address => mapping(uint256 => Ask)) public askForNFT; - - /// /// - /// CREATE ASK /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,-----------. - // / \ |AsksCoreEth| - // Caller `-----+-----' - // | createAsk() | - // | ------------------>| - // | | - // | ----. - // | | store ask metadata - // | <---' - // | | - // | ----. - // | | emit AskCreated() - // | <---' - // Caller ,-----+-----. - // ,-. |AsksCoreEth| - // `-' `-----------' - // /|\ - // | - // / \ - - /// @notice Emitted when an ask is created - /// @param tokenContract The ERC-721 token address of the created ask - /// @param tokenId The ERC-721 token id of the created ask - /// @param seller The seller address of the created ask - /// @param price The price of the created ask - event AskCreated(address indexed tokenContract, uint256 indexed tokenId, address seller, uint256 price); - - /// @notice Creates an ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _price The price to fill the ask - function createAsk( - address _tokenContract, - uint256 _tokenId, - uint256 _price - ) external nonReentrant { - // Get the owner of the specified token - address tokenOwner = IERC721(_tokenContract).ownerOf(_tokenId); - - // Ensure the caller is the owner or an approved operator - require(msg.sender == tokenOwner || IERC721(_tokenContract).isApprovedForAll(tokenOwner, msg.sender), "ONLY_TOKEN_OWNER_OR_OPERATOR"); - - // Store the owner as the seller - askForNFT[_tokenContract][_tokenId].seller = tokenOwner; - - // Store the ask price - // The max value for this module is 2^96 - 1, which is magnitudes higher than the total supply of ETH - askForNFT[_tokenContract][_tokenId].price = uint96(_price); - - emit AskCreated(_tokenContract, _tokenId, tokenOwner, _price); - } - - /// /// - /// UPDATE ASK /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,-----------. - // / \ |AsksCoreEth| - // Caller `-----+-----' - // | setAskPrice() | - // | ------------------>| - // | | - // | ----. - // | | update ask price - // | <---' - // | | - // | ----. - // | | emit AskPriceUpdated() - // | <---' - // Caller ,-----+-----. - // ,-. |AsksCoreEth| - // `-' `-----------' - // /|\ - // | - // / \ - - /// @notice Emitted when an ask is updated - /// @param tokenContract The ERC-721 token address of the updated ask - /// @param tokenId The ERC-721 token id of the updated ask - /// @param seller The user that updated the ask - /// @param price The updated price of the ask - event AskPriceUpdated(address indexed tokenContract, uint256 indexed tokenId, address seller, uint256 price); - - /// @notice Updates the ask price for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _price The ask price to set - function setAskPrice( - address _tokenContract, - uint256 _tokenId, - uint256 _price - ) external nonReentrant { - // Get the ask for the specified token - Ask storage ask = askForNFT[_tokenContract][_tokenId]; - - // Ensure the caller is seller - require(msg.sender == ask.seller, "ONLY_SELLER"); - - // Update the ask price - // The max value for this module is 2^96 - 1, which is magnitudes higher than the total supply of ETH - ask.price = uint96(_price); - - emit AskPriceUpdated(_tokenContract, _tokenId, msg.sender, _price); - } - - /// /// - /// CANCEL ASK /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,-----------. - // / \ |AsksCoreEth| - // Caller `-----+-----' - // | cancelAsk() | - // | ------------------>| - // | | - // | ----. - // | | emit AskCanceled() - // | <---' - // | | - // | ----. - // | | delete ask - // | <---' - // Caller ,-----+-----. - // ,-. |AsksCoreEth| - // `-' `-----------' - // /|\ - // | - // / \ - - /// @notice Emitted when an ask is canceled - /// @param tokenContract The ERC-721 token address of the canceled ask - /// @param tokenId The ERC-721 token id of the canceled ask - /// @param seller The user that canceled the ask - /// @param price The price of the canceled ask - event AskCanceled(address indexed tokenContract, uint256 indexed tokenId, address seller, uint256 price); - - /// @notice Cancels the ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function cancelAsk(address _tokenContract, uint256 _tokenId) external nonReentrant { - // Get the ask for the specified token - Ask memory ask = askForNFT[_tokenContract][_tokenId]; - - // Cache the seller address - address seller = ask.seller; - - // Ensure the caller is the seller or a new token owner - require(msg.sender == seller || msg.sender == IERC721(_tokenContract).ownerOf(_tokenId), "ONLY_SELLER_OR_TOKEN_OWNER"); - - emit AskCanceled(_tokenContract, _tokenId, seller, ask.price); - - // Remove the ask from storage - delete askForNFT[_tokenContract][_tokenId]; - } - - /// /// - /// FILL ASK /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,-----------. ,--------------------. - // / \ |AsksCoreEth| |ERC721TransferHelper| - // Caller `-----+-----' `---------+----------' - // | fillAsk() | | - // | ------------------>| | - // | | | - // | ----. | - // | | validate received ETH | - // | <---' | - // | | | - // | ----. | - // | | handle royalty payouts | - // | <---' | - // | | | - // | ----. | - // | | handle seller payout | - // | <---' | - // | | | - // | | transferFrom() | - // | |----------------------------> - // | | | - // | | |----. - // | | | | transfer NFT from seller to buyer - // | | |<---' - // | | | - // | ----. | - // | | emit AskFilled() | - // | <---' | - // | | | - // | ----. - // | | delete ask from contract - // | <---' - // Caller ,-----+-----. ,---------+----------. - // ,-. |AsksCoreEth| |ERC721TransferHelper| - // `-' `-----------' `--------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an ask is filled - /// @param tokenContract The ERC-721 token address of the filled ask - /// @param tokenId The ERC-721 token id of the filled ask - /// @param buyer The buyer address of the filled ask - /// @param seller The seller address of the filled ask - /// @param price The price of the filled ask - event AskFilled(address indexed tokenContract, uint256 indexed tokenId, address buyer, address seller, uint256 price); - - /// @notice Fills the ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function fillAsk(address _tokenContract, uint256 _tokenId) external payable nonReentrant { - // Get the ask for the specified token - Ask memory ask = askForNFT[_tokenContract][_tokenId]; - - // Cache the seller - address seller = ask.seller; - - // Ensure the ask is active - require(seller != address(0), "INACTIVE_ASK"); - - // Cache the price - uint256 price = ask.price; - - // Ensure the attached ETH matches the price - require(msg.value == price, "MUST_MATCH_PRICE"); - - // Payout associated token royalties, if any - (uint256 remainingProfit, ) = _handleRoyaltyPayout(_tokenContract, _tokenId, price, address(0), 300000); - - // Payout the module fee, if configured - remainingProfit = _handleProtocolFeePayout(remainingProfit, address(0)); - - // Transfer the remaining profit to the seller - _handleOutgoingTransfer(seller, remainingProfit, address(0), 50000); - - // Transfer the NFT to the buyer - // Reverts if the seller did not approve the ERC721TransferHelper or no longer owns the token - erc721TransferHelper.transferFrom(_tokenContract, seller, msg.sender, _tokenId); - - emit AskFilled(_tokenContract, _tokenId, msg.sender, seller, price); - - // Remove the ask from storage - delete askForNFT[_tokenContract][_tokenId]; - } -} diff --git a/contracts/modules/Asks/Core/ETH/IAsksCoreEth.sol b/contracts/modules/Asks/Core/ETH/IAsksCoreEth.sol deleted file mode 100644 index 502cbeac..00000000 --- a/contracts/modules/Asks/Core/ETH/IAsksCoreEth.sol +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -/// @title IAsksCoreEth -/// @author kulkarohan -/// @notice Interface for Asks Core ETH -interface IAsksCoreEth { - /// @notice Creates an ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _price The price to fill the ask - function createAsk( - address _tokenContract, - uint256 _tokenId, - uint256 _price - ) external; - - /// @notice Updates the ask price for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _price The ask price to set - function setAskPrice( - address _tokenContract, - uint256 _tokenId, - uint256 _price - ) external; - - /// @notice Cancels the ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function cancelAsk(address _tokenContract, uint256 _tokenId) external; - - /// @notice Fills the ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function fillAsk(address _tokenContract, uint256 _tokenId) external payable; -} diff --git a/contracts/modules/Asks/Omnibus/AsksDataStorage.sol b/contracts/modules/Asks/Omnibus/AsksDataStorage.sol deleted file mode 100644 index 80ec628b..00000000 --- a/contracts/modules/Asks/Omnibus/AsksDataStorage.sol +++ /dev/null @@ -1,167 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -contract AsksDataStorage { - struct StoredAsk { - uint256 price; - address seller; - uint32 features; - mapping(uint32 => uint256) featureData; - } - - mapping(address => mapping(uint256 => StoredAsk)) public askForNFT; - - uint32 constant FEATURE_MASK_LISTING_FEE = 1 << 3; - uint32 constant FEATURE_MASK_FINDERS_FEE = 1 << 4; - uint32 constant FEATURE_MASK_ERC20_CURRENCY = 1 << 5; - uint32 constant FEATURE_MASK_TOKEN_GATE = 1 << 6; - uint32 constant FEATURE_MASK_RECIPIENT_OR_EXPIRY = 1 << 7; - uint32 constant FEATURE_MASK_BUYER = 1 << 8; - - function _getListingFee(StoredAsk storage ask) internal view returns (uint16 listingFeeBps, address listingFeeRecipient) { - uint256 data = ask.featureData[FEATURE_MASK_LISTING_FEE]; - listingFeeBps = uint16(data); - listingFeeRecipient = address(uint160(data >> 16)); - } - - function _setListingFee( - StoredAsk storage ask, - uint16 listingFeeBps, - address listingFeeRecipient - ) internal { - ask.features |= FEATURE_MASK_LISTING_FEE; - ask.featureData[FEATURE_MASK_LISTING_FEE] = listingFeeBps | (uint256(uint160(listingFeeRecipient)) << 16); - } - - function _getFindersFee(StoredAsk storage ask) internal view returns (uint16) { - return uint16(ask.featureData[FEATURE_MASK_FINDERS_FEE]); - } - - function _setFindersFee(StoredAsk storage ask, uint16 _findersFeeBps) internal { - ask.features |= FEATURE_MASK_FINDERS_FEE; - ask.featureData[FEATURE_MASK_FINDERS_FEE] = uint256(_findersFeeBps); - } - - function _getAskTokenGate(StoredAsk storage auction) internal view returns (address token, uint256 minAmount) { - token = address(uint160(auction.featureData[FEATURE_MASK_TOKEN_GATE])); - minAmount = auction.featureData[FEATURE_MASK_TOKEN_GATE + 1]; - } - - function _setTokenGate( - StoredAsk storage ask, - address token, - uint256 minAmount - ) internal { - ask.features |= FEATURE_MASK_TOKEN_GATE; - ask.featureData[FEATURE_MASK_TOKEN_GATE] = uint256(uint160(token)); - ask.featureData[FEATURE_MASK_TOKEN_GATE + 1] = minAmount; - } - - function _getExpiryAndFundsRecipient(StoredAsk storage ask) internal view returns (uint96 expiry, address fundsRecipient) { - uint256 data = ask.featureData[FEATURE_MASK_RECIPIENT_OR_EXPIRY]; - expiry = uint96(data); - fundsRecipient = address(uint160(data >> 96)); - } - - function _setExpiryAndFundsRecipient( - StoredAsk storage ask, - uint96 expiry, - address fundsRecipient - ) internal { - ask.features |= FEATURE_MASK_RECIPIENT_OR_EXPIRY; - ask.featureData[FEATURE_MASK_RECIPIENT_OR_EXPIRY] = expiry | (uint256(uint160(fundsRecipient)) << 96); - } - - function _getERC20CurrencyWithFallback(StoredAsk storage ask) internal view returns (address) { - if (!_hasFeature(ask.features, FEATURE_MASK_ERC20_CURRENCY)) { - return address(0); - } - return address(uint160(ask.featureData[FEATURE_MASK_ERC20_CURRENCY])); - } - - function _setERC20Currency(StoredAsk storage ask, address currency) internal { - ask.features |= FEATURE_MASK_ERC20_CURRENCY; - ask.featureData[FEATURE_MASK_ERC20_CURRENCY] = uint256(uint160(currency)); - } - - function _setETHorERC20Currency(StoredAsk storage ask, address currency) internal { - // turn off erc20 feature if previous currency was erc20 and new currency is eth - if (currency == address(0) && _hasFeature(ask.features, FEATURE_MASK_ERC20_CURRENCY)) { - ask.features &= ~FEATURE_MASK_ERC20_CURRENCY; - } - if (currency != address(0)) { - // turn on erc20 feature if previous currency was eth and new currency is erc20 - if (!_hasFeature(ask.features, FEATURE_MASK_ERC20_CURRENCY)) { - ask.features |= FEATURE_MASK_ERC20_CURRENCY; - } - ask.featureData[FEATURE_MASK_ERC20_CURRENCY] = uint256(uint160(currency)); - } - } - - function _getBuyerWithFallback(StoredAsk storage ask) internal view returns (address) { - if (!_hasFeature(ask.features, FEATURE_MASK_BUYER)) { - return address(0); - } - return address(uint160(ask.featureData[FEATURE_MASK_BUYER])); - } - - function _setBuyer(StoredAsk storage ask, address buyer) internal { - ask.features |= FEATURE_MASK_BUYER; - ask.featureData[FEATURE_MASK_BUYER] = uint256(uint160(buyer)); - } - - struct FullAsk { - uint256 price; - address seller; - uint96 expiry; - uint256 tokenGateMinAmount; - address tokenGateToken; - address sellerFundsRecipient; - address currency; - address buyer; - address listingFeeRecipient; - uint16 listingFeeBps; - uint16 findersFeeBps; - } - - function _hasFeature(uint32 features, uint32 feature) internal pure returns (bool) { - return (features & feature) == feature; - } - - function _getFullAsk(StoredAsk storage ask) internal view returns (FullAsk memory) { - uint32 features = ask.features; - FullAsk memory fullAsk; - - fullAsk.currency = _getERC20CurrencyWithFallback(ask); - fullAsk.buyer = _getBuyerWithFallback(ask); - - if (_hasFeature(features, FEATURE_MASK_TOKEN_GATE)) { - (fullAsk.tokenGateToken, fullAsk.tokenGateMinAmount) = _getAskTokenGate(ask); - } - - if (_hasFeature(features, FEATURE_MASK_LISTING_FEE)) { - (fullAsk.listingFeeBps, fullAsk.listingFeeRecipient) = _getListingFee(ask); - } - - if (_hasFeature(features, FEATURE_MASK_FINDERS_FEE)) { - fullAsk.findersFeeBps = _getFindersFee(ask); - } - - if (_hasFeature(features, FEATURE_MASK_ERC20_CURRENCY)) { - fullAsk.currency = _getERC20CurrencyWithFallback(ask); - } - - if (_hasFeature(features, FEATURE_MASK_RECIPIENT_OR_EXPIRY)) { - (fullAsk.expiry, fullAsk.sellerFundsRecipient) = _getExpiryAndFundsRecipient(ask); - } - - if (_hasFeature(features, FEATURE_MASK_BUYER)) { - fullAsk.buyer = _getBuyerWithFallback(ask); - } - - fullAsk.seller = ask.seller; - fullAsk.price = ask.price; - - return fullAsk; - } -} diff --git a/contracts/modules/Asks/Omnibus/AsksOmnibus.sol b/contracts/modules/Asks/Omnibus/AsksOmnibus.sol deleted file mode 100644 index 7545fcdc..00000000 --- a/contracts/modules/Asks/Omnibus/AsksOmnibus.sol +++ /dev/null @@ -1,332 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {ReentrancyGuard} from "@rari-capital/solmate/src/utils/ReentrancyGuard.sol"; -import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import {ERC721TransferHelper} from "../../../transferHelpers/ERC721TransferHelper.sol"; -import {IncomingTransferSupportV1} from "../../../common/IncomingTransferSupport/V1/IncomingTransferSupportV1.sol"; -import {FeePayoutSupportV1} from "../../../common/FeePayoutSupport/FeePayoutSupportV1.sol"; -import {ModuleNamingSupportV1} from "../../../common/ModuleNamingSupport/ModuleNamingSupportV1.sol"; - -import {IAsksOmnibus} from "./IAsksOmnibus.sol"; -import {AsksDataStorage} from "./AsksDataStorage.sol"; - -/// @title Asks -/// @author jgeary -/// @notice Omnibus module for multi-featured asks for ERC-721 tokens -contract AsksOmnibus is IAsksOmnibus, ReentrancyGuard, IncomingTransferSupportV1, FeePayoutSupportV1, ModuleNamingSupportV1, AsksDataStorage { - /// @notice The ZORA ERC-721 Transfer Helper - ERC721TransferHelper public immutable erc721TransferHelper; - - /// @notice Emitted when an ask is created - /// @param tokenContract The ERC-721 token address of the created ask - /// @param tokenId The ERC-721 token ID of the created ask - /// @param ask The metadata of the created ask - event AskCreated(address indexed tokenContract, uint256 indexed tokenId, FullAsk ask); - - /// @notice Emitted when an ask price is updated - /// @param tokenContract The ERC-721 token address of the updated ask - /// @param tokenId The ERC-721 token ID of the updated ask - /// @param ask The metadata of the updated ask - event AskPriceUpdated(address indexed tokenContract, uint256 indexed tokenId, FullAsk ask); - - /// @notice Emitted when an ask is canceled - /// @param tokenContract The ERC-721 token address of the canceled ask - /// @param tokenId The ERC-721 token ID of the canceled ask - /// @param ask The metadata of the canceled ask - event AskCanceled(address indexed tokenContract, uint256 indexed tokenId, FullAsk ask); - - /// @notice Emitted when an ask is filled - /// @param tokenContract The ERC-721 token address of the filled ask - /// @param tokenId The ERC-721 token ID of the filled ask - /// @param buyer The buyer address of the filled ask - /// @param finder The address of finder who referred the ask - /// @param ask The metadata of the filled ask - event AskFilled(address indexed tokenContract, uint256 indexed tokenId, address indexed buyer, address finder, FullAsk ask); - - /// @param _erc20TransferHelper The ZORA ERC-20 Transfer Helper address - /// @param _erc721TransferHelper The ZORA ERC-721 Transfer Helper address - /// @param _royaltyEngine The Manifold Royalty Engine address - /// @param _protocolFeeSettings The ZORA Protocol Fee Settings address - /// @param _weth The WETH token address - constructor( - address _erc20TransferHelper, - address _erc721TransferHelper, - address _royaltyEngine, - address _protocolFeeSettings, - address _weth - ) - IncomingTransferSupportV1(_erc20TransferHelper) - FeePayoutSupportV1(_royaltyEngine, _protocolFeeSettings, _weth, ERC721TransferHelper(_erc721TransferHelper).ZMM().registrar()) - ModuleNamingSupportV1("Asks Omnibus: ERC20 / Finders Fee / Listing Fee / Expiry / Private / Token Gate") - { - erc721TransferHelper = ERC721TransferHelper(_erc721TransferHelper); - } - - /// @notice Implements EIP-165 for standard interface detection - /// @dev `0x01ffc9a7` is the IERC165 interface id - /// @param _interfaceId The identifier of a given interface - /// @return If the given interface is supported - function supportsInterface(bytes4 _interfaceId) external pure returns (bool) { - return _interfaceId == type(IAsksOmnibus).interfaceId || _interfaceId == 0x01ffc9a7; - } - - /// @notice Creates a simple ETH ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _askPrice The ETH price to fill the ask - function createAskMinimal( - address _tokenContract, - uint256 _tokenId, - uint256 _askPrice - ) external nonReentrant { - // Get the owner of the specified token - address tokenOwner = IERC721(_tokenContract).ownerOf(_tokenId); - - // Ensure the caller is the owner or an approved operator - if (msg.sender != tokenOwner && !IERC721(_tokenContract).isApprovedForAll(tokenOwner, msg.sender)) revert NOT_TOKEN_OWNER_OR_OPERATOR(); - - if (!erc721TransferHelper.isModuleApproved(msg.sender)) revert MODULE_NOT_APPROVED(); - if (!IERC721(_tokenContract).isApprovedForAll(tokenOwner, address(erc721TransferHelper))) revert TRANSFER_HELPER_NOT_APPROVED(); - - StoredAsk storage ask = askForNFT[_tokenContract][_tokenId]; - ask.features = 0; - ask.seller = tokenOwner; - ask.price = _askPrice; - - emit AskCreated(_tokenContract, _tokenId, _getFullAsk(ask)); - } - - /// @notice Creates an ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _expiry Timestamp after which the ask expires - /// @param _askPrice The price to fill the ask - /// @param _sellerFundsRecipient Address that receives funds for seller - /// @param _askCurrency Address of ERC20 token (or 0x0 for ETH) - /// @param _buyer Specifid buyer for private asks - /// @param _findersFeeBps Finders fee basis points - /// @param _listingFeeBps Listing fee basis points - /// @param _listingFeeRecipient Listing fee recipient - /// @param _tokenGateToken Token gate erc20 token - /// @param _tokenGateMinAmount Token gate bidder minimum amount - function createAsk( - address _tokenContract, - uint256 _tokenId, - uint96 _expiry, - uint256 _askPrice, - address _sellerFundsRecipient, - address _askCurrency, - address _buyer, - uint16 _findersFeeBps, - uint16 _listingFeeBps, - address _listingFeeRecipient, - address _tokenGateToken, - uint256 _tokenGateMinAmount - ) external nonReentrant { - address tokenOwner = IERC721(_tokenContract).ownerOf(_tokenId); - - if (msg.sender != tokenOwner && !IERC721(_tokenContract).isApprovedForAll(tokenOwner, msg.sender)) revert NOT_TOKEN_OWNER_OR_OPERATOR(); - if (!erc721TransferHelper.isModuleApproved(msg.sender)) revert MODULE_NOT_APPROVED(); - if (!IERC721(_tokenContract).isApprovedForAll(tokenOwner, address(erc721TransferHelper))) revert TRANSFER_HELPER_NOT_APPROVED(); - - StoredAsk storage ask = askForNFT[_tokenContract][_tokenId]; - - ask.features = 0; - - if ((_listingFeeBps > 0 && _listingFeeRecipient == address(0)) || (_listingFeeBps == 0 && _listingFeeRecipient != address(0))) - revert INVALID_LISTING_FEE(); - if (_listingFeeBps + _findersFeeBps > 10000) revert INVALID_FEES(); - - if (_listingFeeBps > 0) { - _setListingFee(ask, _listingFeeBps, _listingFeeRecipient); - } - - if (_findersFeeBps > 0) { - _setFindersFee(ask, _findersFeeBps); - } - - if ((_tokenGateMinAmount > 0 && _tokenGateToken == address(0)) || (_tokenGateMinAmount == 0 && _tokenGateToken != address(0))) - revert INVALID_TOKEN_GATE(); - - if (_tokenGateToken != address(0)) { - _setTokenGate(ask, _tokenGateToken, _tokenGateMinAmount); - } - - if (_expiry > 0 || (_sellerFundsRecipient != address(0) && _sellerFundsRecipient != tokenOwner)) { - if (_expiry != 0 && _expiry <= block.timestamp) revert INVALID_EXPIRY(); - _setExpiryAndFundsRecipient(ask, _expiry, _sellerFundsRecipient); - } - - if (_askCurrency != address(0)) { - _setERC20Currency(ask, _askCurrency); - } - - if (_buyer != address(0)) { - _setBuyer(ask, _buyer); - } - - ask.seller = tokenOwner; - ask.price = _askPrice; - - emit AskCreated(_tokenContract, _tokenId, _getFullAsk(ask)); - } - - /// @notice Updates the price of a given NFT's live ask - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _askPrice The price to fill the ask - /// @param _askCurrency Address of ERC20 token (or 0x0 for ETH) - function setAskPrice( - address _tokenContract, - uint256 _tokenId, - uint256 _askPrice, - address _askCurrency - ) external nonReentrant { - StoredAsk storage ask = askForNFT[_tokenContract][_tokenId]; - - if (msg.sender != ask.seller && !IERC721(_tokenContract).isApprovedForAll(ask.seller, msg.sender)) { - revert NOT_TOKEN_OWNER_OR_OPERATOR(); - } - - ask.price = _askPrice; - - _setETHorERC20Currency(ask, _askCurrency); - - emit AskPriceUpdated(_tokenContract, _tokenId, _getFullAsk(ask)); - } - - /// @notice Cancels an ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function cancelAsk(address _tokenContract, uint256 _tokenId) external nonReentrant { - // Get the ask for the specified token - StoredAsk storage ask = askForNFT[_tokenContract][_tokenId]; - - // If token is still owned by seller, only seller or operator can cancel (otherwise public) - if ( - IERC721(_tokenContract).ownerOf(_tokenId) == ask.seller && - msg.sender != ask.seller && - !IERC721(_tokenContract).isApprovedForAll(ask.seller, msg.sender) - ) { - revert NOT_TOKEN_OWNER_OR_OPERATOR(); - } - - emit AskCanceled(_tokenContract, _tokenId, _getFullAsk(ask)); - - // Remove the ask from storage - delete askForNFT[_tokenContract][_tokenId]; - } - - function _handleListingAndFindersFees( - uint256 _remainingProfit, - StoredAsk storage ask, - address currency, - address finder - ) internal returns (uint256 remainingProfit) { - remainingProfit = _remainingProfit; - uint256 listingFee; - address listingFeeRecipient; - uint256 findersFee; - - if (_hasFeature(ask.features, FEATURE_MASK_LISTING_FEE)) { - uint16 listingFeeBps; - (listingFeeBps, listingFeeRecipient) = _getListingFee(ask); - listingFee = (remainingProfit * listingFeeBps) / 10000; - } - - if (finder != address(0) && _hasFeature(ask.features, FEATURE_MASK_FINDERS_FEE)) { - findersFee = (remainingProfit * _getFindersFee(ask)) / 10000; - } - - if (listingFee > 0) { - _handleOutgoingTransfer(listingFeeRecipient, listingFee, currency, 50000); - remainingProfit -= listingFee; - } - if (findersFee > 0) { - _handleOutgoingTransfer(finder, findersFee, currency, 50000); - remainingProfit -= findersFee; - } - } - - /// @notice Fills an ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _price The ask price - /// @param _currency The ask currency - /// @param _finder The ask finder - function fillAsk( - address _tokenContract, - uint256 _tokenId, - uint256 _price, - address _currency, - address _finder - ) external payable nonReentrant { - // Get the ask for the specified token - StoredAsk storage ask = askForNFT[_tokenContract][_tokenId]; - - // Cache the seller - address seller = ask.seller; - - // Ensure the ask is active - if (seller == address(0)) revert ASK_INACTIVE(); - - // Cache the price - uint256 price = ask.price; - address currency = _getERC20CurrencyWithFallback(ask); - - // Ensure the specified price matches the ask price - if (_price != price || _currency != currency) revert INCORRECT_CURRENCY_OR_AMOUNT(); - - address fundsRecipient = ask.seller; - - if (_hasFeature(ask.features, FEATURE_MASK_RECIPIENT_OR_EXPIRY)) { - (uint96 expiry, address storedFundsRecipient) = _getExpiryAndFundsRecipient(ask); - if (storedFundsRecipient != address(0)) { - fundsRecipient = storedFundsRecipient; - } - if (expiry < block.timestamp) revert ASK_EXPIRED(); - } - - if (_hasFeature(ask.features, FEATURE_MASK_TOKEN_GATE)) { - (address tokenGateToken, uint256 tokenGateMinAmount) = _getAskTokenGate(ask); - if (IERC20(tokenGateToken).balanceOf(msg.sender) < tokenGateMinAmount) revert TOKEN_GATE_INSUFFICIENT_BALANCE(); - } - - if (_hasFeature(ask.features, FEATURE_MASK_BUYER)) { - if (msg.sender != _getBuyerWithFallback(ask)) revert NOT_DESIGNATED_BUYER(); - } - - // Transfer the ask price from the buyer - // If ETH, this reverts if the buyer did not attach enough - // If ERC-20, this reverts if the buyer did not approve the ERC20TransferHelper or does not own the specified tokens - _handleIncomingTransfer(price, currency); - - // Payout associated token royalties, if any - (uint256 remainingProfit, ) = _handleRoyaltyPayout(_tokenContract, _tokenId, price, currency, 300000); - - // Payout the module fee, if configured - remainingProfit = _handleProtocolFeePayout(remainingProfit, currency); - - remainingProfit = _handleListingAndFindersFees(remainingProfit, ask, currency, _finder); - - // Transfer the remaining profit to the seller - _handleOutgoingTransfer(fundsRecipient, remainingProfit, currency, 50000); - - // Transfer the NFT to the buyer - // Reverts if the seller did not approve the ERC721TransferHelper or no longer owns the token - erc721TransferHelper.transferFrom(_tokenContract, seller, msg.sender, _tokenId); - - emit AskFilled(_tokenContract, _tokenId, msg.sender, _finder, _getFullAsk(ask)); - - // Remove the ask from storage - delete askForNFT[_tokenContract][_tokenId]; - } - - function getFullAsk(address _tokenContract, uint256 _tokenId) external view returns (FullAsk memory) { - StoredAsk storage ask = askForNFT[_tokenContract][_tokenId]; - return _getFullAsk(ask); - } -} diff --git a/contracts/modules/Asks/Omnibus/IAsksOmnibus.sol b/contracts/modules/Asks/Omnibus/IAsksOmnibus.sol deleted file mode 100644 index f492f37d..00000000 --- a/contracts/modules/Asks/Omnibus/IAsksOmnibus.sol +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {AsksDataStorage} from "./AsksDataStorage.sol"; - -/// @title IReserveAuctionOmnibus -/// @author kulkarohan -/// @notice Interface for Reserve Auction Core ERC-20 -interface IAsksOmnibus { - error NOT_TOKEN_OWNER_OR_OPERATOR(); - - error MODULE_NOT_APPROVED(); - - error TRANSFER_HELPER_NOT_APPROVED(); - - error INVALID_LISTING_FEE(); - - error INVALID_FEES(); - - error INVALID_TOKEN_GATE(); - - error INVALID_EXPIRY(); - - error ASK_INACTIVE(); - - error ASK_EXPIRED(); - - error INCORRECT_CURRENCY_OR_AMOUNT(); - - error TOKEN_GATE_INSUFFICIENT_BALANCE(); - - error NOT_DESIGNATED_BUYER(); - - function createAskMinimal( - address _tokenContract, - uint256 _tokenId, - uint256 _askPrice - ) external; - - function createAsk( - address _tokenContract, - uint256 _tokenId, - uint96 _expiry, - uint256 _askPrice, - address _sellerFundsRecipient, - address _askCurrency, - address _buyer, - uint16 _findersFeeBps, - uint16 _listingFeeBps, - address _listingFeeRecipient, - address _tokenGateToken, - uint256 _tokenGateMinAmount - ) external; - - function cancelAsk(address _tokenContract, uint256 _tokenId) external; - - function setAskPrice( - address _tokenContract, - uint256 _tokenId, - uint256 _askPrice, - address _askCurrency - ) external; - - function fillAsk( - address _tokenContract, - uint256 _tokenId, - uint256 _price, - address _currency, - address _finder - ) external payable; -} diff --git a/contracts/modules/Asks/Private/ETH/AsksPrivateEth.sol b/contracts/modules/Asks/Private/ETH/AsksPrivateEth.sol deleted file mode 100644 index ff9ba6d5..00000000 --- a/contracts/modules/Asks/Private/ETH/AsksPrivateEth.sol +++ /dev/null @@ -1,333 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {ReentrancyGuard} from "@rari-capital/solmate/src/utils/ReentrancyGuard.sol"; -import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; - -import {ERC721TransferHelper} from "../../../../transferHelpers/ERC721TransferHelper.sol"; -import {FeePayoutSupportV1} from "../../../../common/FeePayoutSupport/FeePayoutSupportV1.sol"; -import {ModuleNamingSupportV1} from "../../../../common/ModuleNamingSupport/ModuleNamingSupportV1.sol"; -import {IAsksPrivateEth} from "./IAsksPrivateEth.sol"; - -/// @title Asks Private ETH -/// @author kulkarohan -/// @notice Module enabling ETH asks for ERC-721 tokens with specified buyers -contract AsksPrivateEth is IAsksPrivateEth, ReentrancyGuard, FeePayoutSupportV1, ModuleNamingSupportV1 { - /// /// - /// IMMUTABLES /// - /// /// - - /// @notice The ZORA ERC-721 Transfer Helper - ERC721TransferHelper public immutable erc721TransferHelper; - - /// /// - /// CONSTRUCTOR /// - /// /// - - /// @param _erc721TransferHelper The ZORA ERC-721 Transfer Helper address - /// @param _royaltyEngine The Manifold Royalty Engine address - /// @param _protocolFeeSettings The ZORA Protocol Fee Settings address - /// @param _weth The WETH token address - constructor( - address _erc721TransferHelper, - address _royaltyEngine, - address _protocolFeeSettings, - address _weth - ) - FeePayoutSupportV1(_royaltyEngine, _protocolFeeSettings, _weth, ERC721TransferHelper(_erc721TransferHelper).ZMM().registrar()) - ModuleNamingSupportV1("Asks Private ETH") - { - erc721TransferHelper = ERC721TransferHelper(_erc721TransferHelper); - } - - /// /// - /// EIP-165 /// - /// /// - - /// @notice Implements EIP-165 for standard interface detection - /// @dev `0x01ffc9a7` is the IERC165 interface id - /// @param _interfaceId The identifier of a given interface - /// @return If the given interface is supported - function supportsInterface(bytes4 _interfaceId) external pure returns (bool) { - return _interfaceId == type(IAsksPrivateEth).interfaceId || _interfaceId == 0x01ffc9a7; - } - - /// /// - /// ASK STORAGE /// - /// /// - - /// @notice The metadata for a given ask - /// @param seller The address of the seller - /// @param price The price to fill the ask - /// @param buyer The address of the buyer - struct Ask { - address seller; - uint96 price; - address buyer; - } - - /// @notice The ask for a given NFT - /// @dev ERC-721 token contract => ERC-721 token id => Ask - mapping(address => mapping(uint256 => Ask)) public askForNFT; - - /// /// - /// CREATE ASK /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,--------------. - // / \ |AsksPrivateEth| - // Caller `------+-------' - // | createAsk() | - // | --------------------> - // | | - // | |----. - // | | | store ask metadata - // | |<---' - // | | - // | |----. - // | | | emit AskCreated() - // | |<---' - // Caller ,------+-------. - // ,-. |AsksPrivateEth| - // `-' `--------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an ask is created - /// @param tokenContract The ERC-721 token address of the created ask - /// @param tokenId The ERC-721 token id of the created ask - /// @param ask The metadata of the created ask - event AskCreated(address indexed tokenContract, uint256 indexed tokenId, Ask ask); - - /// @notice Creates an ask for a given NFT - /// @param _tokenContract The ERC-721 token address - /// @param _tokenId The ERC-721 token id - /// @param _price The price to fill the ask - /// @param _buyer The address to fill the ask - function createAsk( - address _tokenContract, - uint256 _tokenId, - uint256 _price, - address _buyer - ) external nonReentrant { - // Get the owner of the specified token - address tokenOwner = IERC721(_tokenContract).ownerOf(_tokenId); - - // Ensure the caller is the owner or an approved operator - require(msg.sender == tokenOwner || IERC721(_tokenContract).isApprovedForAll(tokenOwner, msg.sender), "ONLY_TOKEN_OWNER_OR_OPERATOR"); - - // Get the storage pointer to the token - Ask storage ask = askForNFT[_tokenContract][_tokenId]; - - // Store the associated metadata - ask.seller = tokenOwner; - ask.price = uint96(_price); - ask.buyer = _buyer; - - emit AskCreated(_tokenContract, _tokenId, ask); - } - - /// /// - /// UPDATE ASK /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,--------------. - // / \ |AsksPrivateEth| - // Caller `------+-------' - // | setAskPrice() | - // | --------------------> - // | | - // | |----. - // | | | update ask price - // | |<---' - // | | - // | |----. - // | | | emit AskPriceUpdated() - // | |<---' - // Caller ,------+-------. - // ,-. |AsksPrivateEth| - // `-' `--------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an ask is updated - /// @param tokenContract The ERC-721 token address of the updated ask - /// @param tokenId The ERC-721 token id of the updated ask - /// @param ask The metadata of the updated ask - event AskPriceUpdated(address indexed tokenContract, uint256 indexed tokenId, Ask ask); - - /// @notice Updates the ask price for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _price The ask price to set - function setAskPrice( - address _tokenContract, - uint256 _tokenId, - uint256 _price - ) external nonReentrant { - // Get the ask for the specified token - Ask storage ask = askForNFT[_tokenContract][_tokenId]; - - // Ensure the caller is seller - require(msg.sender == ask.seller, "ONLY_SELLER"); - - // Update the ask price - ask.price = uint96(_price); - - emit AskPriceUpdated(_tokenContract, _tokenId, ask); - } - - /// /// - /// CANCEL ASK /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,--------------. - // / \ |AsksPrivateEth| - // Caller `------+-------' - // | cancelAsk() | - // | --------------------> - // | | - // | |----. - // | | | emit AskCanceled() - // | |<---' - // | | - // | |----. - // | | | delete ask - // | |<---' - // Caller ,------+-------. - // ,-. |AsksPrivateEth| - // `-' `--------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an ask is canceled - /// @param tokenContract The ERC-721 token address of the canceled ask - /// @param tokenId The ERC-721 token id of the canceled ask - /// @param ask The metadata of the canceled ask - event AskCanceled(address indexed tokenContract, uint256 indexed tokenId, Ask ask); - - /// @notice Cancels the ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function cancelAsk(address _tokenContract, uint256 _tokenId) external nonReentrant { - // Get the ask for the specified token - Ask storage ask = askForNFT[_tokenContract][_tokenId]; - - // Ensure the caller is the seller or a new token owner - require(msg.sender == ask.seller || msg.sender == IERC721(_tokenContract).ownerOf(_tokenId), "ONLY_SELLER_OR_TOKEN_OWNER"); - - emit AskCanceled(_tokenContract, _tokenId, ask); - - // Remove the ask from storage - delete askForNFT[_tokenContract][_tokenId]; - } - - /// /// - /// FILL ASK /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,--------------. ,--------------------. - // / \ |AsksPrivateEth| |ERC721TransferHelper| - // Caller `------+-------' `---------+----------' - // | fillAsk() | | - // | --------------------> | - // | | | - // | |----. | - // | | | validate caller | - // | |<---' | - // | | | - // | |----. | - // | | | validate received ETH | - // | |<---' | - // | | | - // | |----. | - // | | | handle royalty payouts | - // | |<---' | - // | | | - // | |----. | - // | | | handle seller payout | - // | |<---' | - // | | | - // | | transferFrom() | - // | | ----------------------------> - // | | | - // | | |----. - // | | | | transfer NFT from seller to buyer - // | | |<---' - // | | | - // | |----. | - // | | | emit AskFilled() | - // | |<---' | - // | | | - // | |----. - // | | | delete ask from contract - // | |<---' - // Caller ,------+-------. ,---------+----------. - // ,-. |AsksPrivateEth| |ERC721TransferHelper| - // `-' `--------------' `--------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an ask is filled - /// @param tokenContract The ERC-721 token address of the filled ask - /// @param tokenId The ERC-721 token id of the filled ask - /// @param ask The metadata of the filled ask - event AskFilled(address indexed tokenContract, uint256 indexed tokenId, Ask ask); - - /// @notice Fills the ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function fillAsk(address _tokenContract, uint256 _tokenId) external payable nonReentrant { - // Get the ask for the specified token - Ask memory ask = askForNFT[_tokenContract][_tokenId]; - - // Cache the seller - address seller = ask.seller; - - // Ensure the ask is active - require(seller != address(0), "INACTIVE_ASK"); - - // Ensure the caller is the specified buyer - require(msg.sender == ask.buyer, "ONLY_BUYER"); - - // Cache the price - uint256 price = ask.price; - - // Ensure the attached ETH matches the price - require(msg.value == price, "PRICE_MISMATCH"); - - // Payout associated token royalties, if any - (uint256 remainingProfit, ) = _handleRoyaltyPayout(_tokenContract, _tokenId, price, address(0), 300000); - - // Payout the module fee, if configured - remainingProfit = _handleProtocolFeePayout(remainingProfit, address(0)); - - // Transfer the remaining profit to the seller - _handleOutgoingTransfer(seller, remainingProfit, address(0), 50000); - - // Transfer the NFT to the buyer - // Reverts if the seller did not approve the ERC721TransferHelper - erc721TransferHelper.transferFrom(_tokenContract, seller, msg.sender, _tokenId); - - emit AskFilled(_tokenContract, _tokenId, ask); - - // Remove the ask from storage - delete askForNFT[_tokenContract][_tokenId]; - } -} diff --git a/contracts/modules/Asks/Private/ETH/IAsksPrivateEth.sol b/contracts/modules/Asks/Private/ETH/IAsksPrivateEth.sol deleted file mode 100644 index a832c17e..00000000 --- a/contracts/modules/Asks/Private/ETH/IAsksPrivateEth.sol +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -/// @title IAsksPrivateEth -/// @author kulkarohan -/// @notice Interface for Asks Private ETH -interface IAsksPrivateEth { - /// @notice Creates an ask for a given NFT - /// @param _tokenContract The ERC-721 token address - /// @param _tokenId The ERC-721 token id - /// @param _price The price to fill the ask - /// @param _buyer The address to fill the ask - function createAsk( - address _tokenContract, - uint256 _tokenId, - uint256 _price, - address _buyer - ) external; - - /// @notice Updates the ask price for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _price The ask price to set - function setAskPrice( - address _tokenContract, - uint256 _tokenId, - uint256 _price - ) external; - - /// @notice Cancels the ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function cancelAsk(address _tokenContract, uint256 _tokenId) external; - - /// @notice Fills the ask for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function fillAsk(address _tokenContract, uint256 _tokenId) external payable; -} diff --git a/contracts/modules/Asks/V1.1/AsksV1_1.sol b/contracts/modules/Asks/V1.1/AsksV1_1.sol index 28403406..b1d11123 100644 --- a/contracts/modules/Asks/V1.1/AsksV1_1.sol +++ b/contracts/modules/Asks/V1.1/AsksV1_1.sol @@ -8,6 +8,7 @@ import {UniversalExchangeEventV1} from "../../../common/UniversalExchangeEvent/V import {IncomingTransferSupportV1} from "../../../common/IncomingTransferSupport/V1/IncomingTransferSupportV1.sol"; import {FeePayoutSupportV1} from "../../../common/FeePayoutSupport/FeePayoutSupportV1.sol"; import {ModuleNamingSupportV1} from "../../../common/ModuleNamingSupport/ModuleNamingSupportV1.sol"; +import {ITurnstile} from "../../../csr/ITurnstile.sol"; /// @title Asks V1.1 /// @author tbtstl @@ -65,7 +66,7 @@ contract AsksV1_1 is ReentrancyGuard, UniversalExchangeEventV1, IncomingTransfer /// @param _erc20TransferHelper The ZORA ERC-20 Transfer Helper address /// @param _erc721TransferHelper The ZORA ERC-721 Transfer Helper address - /// @param _royaltyEngine The Manifold Royalty Engine address + /// @param _royaltyEngine The Manifold Royalty Engine address << @note this was simplified for Canto implementation /// @param _protocolFeeSettings The ZoraProtocolFeeSettingsV1 address /// @param _wethAddress The WETH token address constructor( @@ -80,6 +81,7 @@ contract AsksV1_1 is ReentrancyGuard, UniversalExchangeEventV1, IncomingTransfer ModuleNamingSupportV1("Asks: v1.1") { erc721TransferHelper = ERC721TransferHelper(_erc721TransferHelper); + ITurnstile(0xEcf044C5B4b867CFda001101c617eCd347095B44).register(msg.sender); //sets Canto CSR parameters } // ,-. @@ -158,6 +160,56 @@ contract AsksV1_1 is ReentrancyGuard, UniversalExchangeEventV1, IncomingTransfer emit AskCreated(_tokenContract, _tokenId, askForNFT[_tokenContract][_tokenId]); } + /// @notice Creates the ask for an array of given NFTs within the same contract + /// @param _tokenContract The address of the ERC-721 token to be sold + /// @param _tokenIds[] Array of IDS of the ERC-721 token to be sold + /// @param _askPrices[] The prices to fill the asks + /// @param _askCurrency The address of the ERC-20 token required to fill, or address(0) for ETH + /// @param _sellerFundsRecipient The address to send funds once the ask is filled + /// @param _findersFeeBps The bps of the ask price (post-royalties) to be sent to the referrer of the sale + function createAsks( + address _tokenContract, + uint256[] memory _tokenIds, + uint256[] memory _askPrices, + address _askCurrency, + address _sellerFundsRecipient, + uint16 _findersFeeBps + ) external nonReentrant { + require(_tokenIds.length == _askPrices.length, "Unbalanced arrays"); + + address tokenOwner; + + for (uint256 i = 0; i < _tokenIds.length; ++i) { + tokenOwner = IERC721(_tokenContract).ownerOf(_tokenIds[i]); + + require( + msg.sender == tokenOwner || IERC721(_tokenContract).isApprovedForAll(tokenOwner, msg.sender), + "createAsk must be token owner or operator" + ); + require(erc721TransferHelper.isModuleApproved(msg.sender), "createAsk must approve AsksV1 module"); + require( + IERC721(_tokenContract).isApprovedForAll(tokenOwner, address(erc721TransferHelper)), + "createAsk must approve ERC721TransferHelper as operator" + ); + require(_findersFeeBps <= 10000, "createAsk finders fee bps must be less than or equal to 10000"); + require(_sellerFundsRecipient != address(0), "createAsk must specify _sellerFundsRecipient"); + + if (askForNFT[_tokenContract][_tokenIds[i]].seller != address(0)) { + _cancelAsk(_tokenContract, _tokenIds[i]); + } + + askForNFT[_tokenContract][_tokenIds[i]] = Ask({ + seller: tokenOwner, + sellerFundsRecipient: _sellerFundsRecipient, + askCurrency: _askCurrency, + findersFeeBps: _findersFeeBps, + askPrice: _askPrices[i] + }); + + emit AskCreated(_tokenContract, _tokenIds[i], askForNFT[_tokenContract][_tokenIds[i]]); + } + } + // ,-. // `-' // /|\ @@ -201,6 +253,31 @@ contract AsksV1_1 is ReentrancyGuard, UniversalExchangeEventV1, IncomingTransfer emit AskPriceUpdated(_tokenContract, _tokenId, ask); } + /// @notice Updates the ask prices for an array of given NFT within the same collection + /// @param _tokenContract The address of the ERC-721 token + /// @param _tokenIds[] Array of IDs of the ERC-721 token + /// @param _askPrices[] Array of ask prices to set + /// @param _askCurrency The address of the ERC-20 token required to fill, or address(0) for ETH + function setAskPrices( + address _tokenContract, + uint256[] memory _tokenIds, + uint256[] memory _askPrices, + address _askCurrency + ) external nonReentrant { + require(_tokenIds.length == _askPrices.length, "Unbalanced arrays"); + + for (uint256 i = 0; i < _tokenIds.length; ++i) { + Ask storage ask = askForNFT[_tokenContract][_tokenIds[i]]; + + require(ask.seller == msg.sender, "setAskPrice must be seller"); + + ask.askPrice = _askPrices[i]; + ask.askCurrency = _askCurrency; + + emit AskPriceUpdated(_tokenContract, _tokenIds[i], ask); + } + } + // ,-. // `-' // /|\ @@ -224,6 +301,7 @@ contract AsksV1_1 is ReentrancyGuard, UniversalExchangeEventV1, IncomingTransfer // | // / \ /// @notice Cancels the ask for a given NFT + /// @notice adds support for Ask cancellation by ZMM registrar /// @param _tokenContract The address of the ERC-721 token /// @param _tokenId The ID of the ERC-721 token function cancelAsk(address _tokenContract, uint256 _tokenId) external nonReentrant { @@ -231,13 +309,32 @@ contract AsksV1_1 is ReentrancyGuard, UniversalExchangeEventV1, IncomingTransfer address tokenOwner = IERC721(_tokenContract).ownerOf(_tokenId); require( - msg.sender == tokenOwner || IERC721(_tokenContract).isApprovedForAll(tokenOwner, msg.sender), - "cancelAsk must be token owner or operator" + msg.sender == tokenOwner || + IERC721(_tokenContract).isApprovedForAll(tokenOwner, msg.sender) || + msg.sender == erc721TransferHelper.ZMM().registrar(), + "cancelAsk must be token owner, operator, or registrar" ); _cancelAsk(_tokenContract, _tokenId); } + /// @notice Cancels the asks for an Array of given NFTs in the same collection + /// @param _tokenContract The address of the ERC-721 token + /// @param _tokenIds[] Array IDs of the ERC-721 token + function cancelAsks(address _tokenContract, uint256[] memory _tokenIds) external nonReentrant { + for (uint256 i = 0; i < _tokenIds.length; ++i) { + require(askForNFT[_tokenContract][_tokenIds[i]].seller != address(0), "cancelAsk ask doesn't exist"); + + address tokenOwner = IERC721(_tokenContract).ownerOf(_tokenIds[i]); + require( + msg.sender == tokenOwner || IERC721(_tokenContract).isApprovedForAll(tokenOwner, msg.sender), + "cancelAsk must be token owner, or operator" + ); + + _cancelAsk(_tokenContract, _tokenIds[i]); + } + } + // ,-. // `-' // /|\ @@ -309,6 +406,7 @@ contract AsksV1_1 is ReentrancyGuard, UniversalExchangeEventV1, IncomingTransfer Ask storage ask = askForNFT[_tokenContract][_tokenId]; require(ask.seller != address(0), "fillAsk must be active ask"); + require(ask.seller == IERC721(_tokenContract).ownerOf(_tokenId), "fillAsk set by former token owner"); // adding a check for stale asks require(ask.askCurrency == _fillCurrency, "fillAsk _fillCurrency must match ask currency"); require(ask.askPrice == _fillAmount, "fillAsk _fillAmount must match ask amount"); @@ -344,6 +442,62 @@ contract AsksV1_1 is ReentrancyGuard, UniversalExchangeEventV1, IncomingTransfer delete askForNFT[_tokenContract][_tokenId]; } + /// @notice Fills the ask for an array of given NFT within the same contract, transferring the ETH/ERC-20 to the seller and NFTs to the buyer + /// @param _tokenContract The address of the ERC-721 token + /// @param _tokenIds[] The IDs of the ERC-721 token + /// @param _fillCurrencies[] The address of the ERC-20 tokens using to fill, or address(0) for ETH + /// @param _fillAmounts[] The amounts to fill the ask + /// @param _finder The address of the ask referrer + function fillAsks( + address _tokenContract, + uint256[] memory _tokenIds, + address[] memory _fillCurrencies, + uint256[] memory _fillAmounts, + address _finder + ) external payable nonReentrant { + require(_tokenIds.length == _fillCurrencies.length && _tokenIds.length == _fillAmounts.length, "Unbalanced arrays"); + + for (uint256 i = 0; i < _tokenIds.length; ++i) { + Ask storage ask = askForNFT[_tokenContract][_tokenIds[i]]; + + require(ask.seller != address(0), "fillAsk must be active ask"); + require(ask.seller == IERC721(_tokenContract).ownerOf(_tokenIds[i]), "fillAsk set by former token owner"); // adding a check for stale asks + require(ask.askCurrency == _fillCurrencies[i], "fillAsk _fillCurrency must match ask currency"); + require(ask.askPrice == _fillAmounts[i], "fillAsk _fillAmount must match ask amount"); + + // Ensure ETH/ERC-20 payment from buyer is valid and take custody + _handleIncomingTransfer(ask.askPrice, ask.askCurrency); + + // Payout respective parties, ensuring royalties are honored + (uint256 remainingProfit, ) = _handleRoyaltyPayout(_tokenContract, _tokenIds[i], ask.askPrice, ask.askCurrency, USE_ALL_GAS_FLAG); + + // Payout optional protocol fee + remainingProfit = _handleProtocolFeePayout(remainingProfit, ask.askCurrency); + + // Payout optional finder fee + if (_finder != address(0)) { + uint256 findersFee = (remainingProfit * ask.findersFeeBps) / 10000; + _handleOutgoingTransfer(_finder, findersFee, ask.askCurrency, USE_ALL_GAS_FLAG); + + remainingProfit = remainingProfit - findersFee; + } + + // Transfer remaining ETH/ERC-20 to seller + _handleOutgoingTransfer(ask.sellerFundsRecipient, remainingProfit, ask.askCurrency, USE_ALL_GAS_FLAG); + + // Transfer NFT to buyer + erc721TransferHelper.transferFrom(_tokenContract, ask.seller, msg.sender, _tokenIds[i]); + + ExchangeDetails memory userAExchangeDetails = ExchangeDetails({tokenContract: _tokenContract, tokenId: _tokenIds[i], amount: 1}); + ExchangeDetails memory userBExchangeDetails = ExchangeDetails({tokenContract: ask.askCurrency, tokenId: 0, amount: ask.askPrice}); + + emit ExchangeExecuted(ask.seller, msg.sender, userAExchangeDetails, userBExchangeDetails); + emit AskFilled(_tokenContract, _tokenIds[i], msg.sender, _finder, ask); + + delete askForNFT[_tokenContract][_tokenIds[i]]; + } + } + /// @dev Deletes canceled and invalid asks /// @param _tokenContract The address of the ERC-721 token /// @param _tokenId The ID of the ERC-721 token diff --git a/contracts/modules/Offers/Omnibus/IOffersOmnibus.sol b/contracts/modules/Offers/Omnibus/IOffersOmnibus.sol deleted file mode 100644 index 486906cd..00000000 --- a/contracts/modules/Offers/Omnibus/IOffersOmnibus.sol +++ /dev/null @@ -1,81 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {OffersDataStorage} from "./OffersDataStorage.sol"; - -/// @title IOffersOmnibus -/// @author jgeary -/// @notice Interface for Offers Omnibus -interface IOffersOmnibus { - error INSUFFICIENT_ALLOWANCE(); - - error MODULE_NOT_APPROVED(); - - error NO_ZERO_OFFERS(); - - error MSG_VALUE_NEQ_ZERO_WITH_OTHER_CURRENCY(); - - error INSUFFICIENT_BALANCE(); - - error MSG_VALUE_NEQ_OFFER_AMOUNT(); - - error INVALID_FEES(); - - error INVALID_EXPIRY(); - - error CALLER_NOT_MAKER(); - - error SAME_OFFER(); - - error INACTIVE_OFFER(); - - error NOT_TOKEN_OWNER(); - - error INCORRECT_CURRENCY_OR_AMOUNT(); - - error TOKEN_TRANSFER_AMOUNT_INCORRECT(); - - error OFFER_EXPIRED(); - - function createOfferMinimal(address _tokenContract, uint256 _tokenId) external payable returns (uint256); - - function createOffer( - address _tokenContract, - uint256 _tokenId, - address _offerCurrency, - uint256 _offerAmount, - uint96 _expiry, - uint16 _findersFeeBps, - uint16 _listingFeeBps, - address _listingFeeRecipient - ) external payable returns (uint256); - - function setOfferAmount( - address _tokenContract, - uint256 _tokenId, - uint256 _offerId, - address _offerCurrency, - uint256 _offerAmount - ) external payable; - - function cancelOffer( - address _tokenContract, - uint256 _tokenId, - uint256 _offerId - ) external; - - function fillOffer( - address _tokenContract, - uint256 _tokenId, - uint256 _offerId, - uint256 _amount, - address _currency, - address _finder - ) external; - - function getFullOffer( - address _tokenContract, - uint256 _tokenId, - uint256 _offerId - ) external view returns (OffersDataStorage.FullOffer memory); -} diff --git a/contracts/modules/Offers/Omnibus/OffersDataStorage.sol b/contracts/modules/Offers/Omnibus/OffersDataStorage.sol deleted file mode 100644 index 9b6fdbbd..00000000 --- a/contracts/modules/Offers/Omnibus/OffersDataStorage.sol +++ /dev/null @@ -1,119 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -contract OffersDataStorage { - struct StoredOffer { - uint256 amount; - address maker; - uint32 features; - mapping(uint32 => uint256) featureData; - } - - mapping(address => mapping(uint256 => mapping(uint256 => StoredOffer))) public offers; - - uint256 public offerCount; - - mapping(address => mapping(uint256 => uint256[])) public offersForNFT; - - uint32 constant FEATURE_MASK_LISTING_FEE = 1 << 3; - uint32 constant FEATURE_MASK_FINDERS_FEE = 1 << 4; - uint32 constant FEATURE_MASK_EXPIRY = 1 << 5; - uint32 constant FEATURE_MASK_ERC20_CURRENCY = 1 << 6; - - function _getListingFee(StoredOffer storage offer) internal view returns (uint16 listingFeeBps, address listingFeeRecipient) { - uint256 data = offer.featureData[FEATURE_MASK_LISTING_FEE]; - listingFeeBps = uint16(data); - listingFeeRecipient = address(uint160(data >> 16)); - } - - function _setListingFee( - StoredOffer storage offer, - uint16 listingFeeBps, - address listingFeeRecipient - ) internal { - offer.features |= FEATURE_MASK_LISTING_FEE; - offer.featureData[FEATURE_MASK_LISTING_FEE] = listingFeeBps | (uint256(uint160(listingFeeRecipient)) << 16); - } - - function _getFindersFee(StoredOffer storage offer) internal view returns (uint16) { - return uint16(offer.featureData[FEATURE_MASK_FINDERS_FEE]); - } - - function _setFindersFee(StoredOffer storage offer, uint16 _findersFeeBps) internal { - offer.features |= FEATURE_MASK_FINDERS_FEE; - offer.featureData[FEATURE_MASK_FINDERS_FEE] = uint256(_findersFeeBps); - } - - function _getExpiry(StoredOffer storage offer) internal view returns (uint96 expiry) { - uint256 data = offer.featureData[FEATURE_MASK_EXPIRY]; - expiry = uint96(data); - } - - function _setExpiry(StoredOffer storage offer, uint96 expiry) internal { - offer.features |= FEATURE_MASK_EXPIRY; - offer.featureData[FEATURE_MASK_EXPIRY] = expiry; - } - - function _getERC20CurrencyWithFallback(StoredOffer storage offer) internal view returns (address) { - if (!_hasFeature(offer.features, FEATURE_MASK_ERC20_CURRENCY)) { - return address(0); - } - return address(uint160(offer.featureData[FEATURE_MASK_ERC20_CURRENCY])); - } - - function _setERC20Currency(StoredOffer storage offer, address currency) internal { - offer.features |= FEATURE_MASK_ERC20_CURRENCY; - offer.featureData[FEATURE_MASK_ERC20_CURRENCY] = uint256(uint160(currency)); - } - - function _setETHorERC20Currency(StoredOffer storage offer, address currency) internal { - // turn off erc20 feature if previous currency was erc20 and new currency is eth - if (currency == address(0) && _hasFeature(offer.features, FEATURE_MASK_ERC20_CURRENCY)) { - offer.features &= ~FEATURE_MASK_ERC20_CURRENCY; - } - if (currency != address(0)) { - // turn on erc20 feature if previous currency was eth and new currency is erc20 - if (!_hasFeature(offer.features, FEATURE_MASK_ERC20_CURRENCY)) { - offer.features |= FEATURE_MASK_ERC20_CURRENCY; - } - offer.featureData[FEATURE_MASK_ERC20_CURRENCY] = uint256(uint160(currency)); - } - } - - struct FullOffer { - uint256 amount; - address maker; - uint96 expiry; - address currency; - uint16 findersFeeBps; - uint16 listingFeeBps; - address listingFeeRecipient; - } - - function _hasFeature(uint32 features, uint32 feature) internal pure returns (bool) { - return (features & feature) == feature; - } - - function _getFullOffer(StoredOffer storage offer) internal view returns (FullOffer memory) { - uint32 features = offer.features; - FullOffer memory fullOffer; - - if (_hasFeature(features, FEATURE_MASK_LISTING_FEE)) { - (fullOffer.listingFeeBps, fullOffer.listingFeeRecipient) = _getListingFee(offer); - } - - if (_hasFeature(features, FEATURE_MASK_FINDERS_FEE)) { - fullOffer.findersFeeBps = _getFindersFee(offer); - } - - if (_hasFeature(features, FEATURE_MASK_EXPIRY)) { - fullOffer.expiry = _getExpiry(offer); - } - - fullOffer.currency = _getERC20CurrencyWithFallback(offer); - fullOffer.maker = offer.maker; - fullOffer.amount = offer.amount; - - return fullOffer; - } -} diff --git a/contracts/modules/Offers/Omnibus/OffersOmnibus.sol b/contracts/modules/Offers/Omnibus/OffersOmnibus.sol deleted file mode 100644 index ca1d84f6..00000000 --- a/contracts/modules/Offers/Omnibus/OffersOmnibus.sol +++ /dev/null @@ -1,328 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {ReentrancyGuard} from "@rari-capital/solmate/src/utils/ReentrancyGuard.sol"; -import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; - -import {ERC721TransferHelper} from "../../../transferHelpers/ERC721TransferHelper.sol"; -import {IncomingTransferSupportV1} from "../../../common/IncomingTransferSupport/V1/IncomingTransferSupportV1.sol"; -import {FeePayoutSupportV1} from "../../../common/FeePayoutSupport/FeePayoutSupportV1.sol"; -import {ModuleNamingSupportV1} from "../../../common/ModuleNamingSupport/ModuleNamingSupportV1.sol"; - -import {IOffersOmnibus} from "./IOffersOmnibus.sol"; -import {OffersDataStorage} from "./OffersDataStorage.sol"; - -/// @title Offers Omnibus -/// @author jgeary -/// @notice Omnibus module for multi-featured offers for ERC-721 tokens -contract OffersOmnibus is IOffersOmnibus, ReentrancyGuard, IncomingTransferSupportV1, FeePayoutSupportV1, ModuleNamingSupportV1, OffersDataStorage { - /// @dev The indicator to pass all remaining gas when paying out royalties - uint256 private constant USE_ALL_GAS_FLAG = 0; - - /// @notice The ZORA ERC-721 Transfer Helper - ERC721TransferHelper public immutable erc721TransferHelper; - - /// @notice Emitted when an offer is created - /// @param tokenContract The ERC-721 token address of the created offer - /// @param tokenId The ERC-721 token ID of the created offer - /// @param id The ID of the created offer - /// @param offer The metadata of the created offer - event OfferCreated(address indexed tokenContract, uint256 indexed tokenId, uint256 indexed id, FullOffer offer); - - /// @notice Emitted when an offer amount is updated - /// @param tokenContract The ERC-721 token address of the updated offer - /// @param tokenId The ERC-721 token ID of the updated offer - /// @param id The ID of the updated offer - /// @param offer The metadata of the updated offer - event OfferUpdated(address indexed tokenContract, uint256 indexed tokenId, uint256 indexed id, FullOffer offer); - - /// @notice Emitted when an offer is canceled - /// @param tokenContract The ERC-721 token address of the canceled offer - /// @param tokenId The ERC-721 token ID of the canceled offer - /// @param id The ID of the canceled offer - /// @param offer The metadata of the canceled offer - event OfferCanceled(address indexed tokenContract, uint256 indexed tokenId, uint256 indexed id, FullOffer offer); - - /// @notice Emitted when an offer is filled - /// @param tokenContract The ERC-721 token address of the filled offer - /// @param tokenId The ERC-721 token ID of the filled offer - /// @param id The ID of the filled offer - /// @param taker The address of the taker who filled the offer - /// @param finder The address of the finder who referred the offer - /// @param offer The metadata of the filled offer - event OfferFilled(address indexed tokenContract, uint256 indexed tokenId, uint256 indexed id, address taker, address finder, FullOffer offer); - - /// @param _erc20TransferHelper The ZORA ERC-20 Transfer Helper address - /// @param _erc721TransferHelper The ZORA ERC-721 Transfer Helper address - /// @param _royaltyEngine The Manifold Royalty Engine address - /// @param _protocolFeeSettings The ZORA Protocol Fee Settings address - /// @param _weth The WETH token address - constructor( - address _erc20TransferHelper, - address _erc721TransferHelper, - address _royaltyEngine, - address _protocolFeeSettings, - address _weth - ) - IncomingTransferSupportV1(_erc20TransferHelper) - FeePayoutSupportV1(_royaltyEngine, _protocolFeeSettings, _weth, ERC721TransferHelper(_erc721TransferHelper).ZMM().registrar()) - ModuleNamingSupportV1("Offers Omnibus") - { - erc721TransferHelper = ERC721TransferHelper(_erc721TransferHelper); - } - - /// @notice Implements EIP-165 for standard interface detection - /// @dev `0x01ffc9a7` is the IERC165 interface id - /// @param _interfaceId The identifier of a given interface - /// @return If the given interface is supported - function supportsInterface(bytes4 _interfaceId) external pure returns (bool) { - return _interfaceId == type(IOffersOmnibus).interfaceId || _interfaceId == type(IERC165).interfaceId; - } - - /// @notice Creates a simple WETH offer for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function createOfferMinimal(address _tokenContract, uint256 _tokenId) external payable nonReentrant returns (uint256) { - uint256 _offerAmount = msg.value; - weth.deposit{value: msg.value}(); - weth.transferFrom(address(this), msg.sender, _offerAmount); - - if (weth.allowance(msg.sender, address(erc20TransferHelper)) < _offerAmount) revert INSUFFICIENT_ALLOWANCE(); - if (!erc721TransferHelper.isModuleApproved(msg.sender)) revert MODULE_NOT_APPROVED(); - - ++offerCount; - - StoredOffer storage offer = offers[_tokenContract][_tokenId][offerCount]; - offer.amount = _offerAmount; - offer.maker = msg.sender; - offer.features = 0; - - offersForNFT[_tokenContract][_tokenId].push(offerCount); - emit OfferCreated(_tokenContract, _tokenId, offerCount, _getFullOffer(offer)); - return offerCount; - } - - /// @notice Creates an offer for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _offerAmount The amount of ERC20 token offered - /// @param _offerCurrency Address of ERC20 token - /// @param _expiry Timestamp after which the ask expires - /// @param _findersFeeBps Finders fee basis points - /// @param _listingFeeBps Listing fee basis points - /// @param _listingFeeRecipient Listing fee recipient - function createOffer( - address _tokenContract, - uint256 _tokenId, - address _offerCurrency, - uint256 _offerAmount, - uint96 _expiry, - uint16 _findersFeeBps, - uint16 _listingFeeBps, - address _listingFeeRecipient - ) external payable nonReentrant returns (uint256) { - if (_offerAmount == 0) revert NO_ZERO_OFFERS(); - - ++offerCount; - offersForNFT[_tokenContract][_tokenId].push(offerCount); - StoredOffer storage offer = offers[_tokenContract][_tokenId][offerCount]; - - if (_offerCurrency != address(0)) { - if (msg.value > 0) revert MSG_VALUE_NEQ_ZERO_WITH_OTHER_CURRENCY(); - IERC20 token = IERC20(_offerCurrency); - if (token.balanceOf(msg.sender) < _offerAmount) revert INSUFFICIENT_BALANCE(); - if (token.allowance(msg.sender, address(erc20TransferHelper)) < _offerAmount) revert INSUFFICIENT_ALLOWANCE(); - } else { - if (msg.value != _offerAmount) revert MSG_VALUE_NEQ_OFFER_AMOUNT(); - weth.deposit{value: msg.value}(); - weth.transferFrom(address(this), msg.sender, _offerAmount); - if (weth.balanceOf(msg.sender) < _offerAmount) revert INSUFFICIENT_BALANCE(); - if (weth.allowance(msg.sender, address(erc20TransferHelper)) < _offerAmount) revert INSUFFICIENT_ALLOWANCE(); - } - if (!erc721TransferHelper.isModuleApproved(msg.sender)) revert MODULE_NOT_APPROVED(); - - offer.maker = msg.sender; - offer.amount = _offerAmount; - offer.features = 0; - - _setETHorERC20Currency(offer, _offerCurrency); - - if (_findersFeeBps + _listingFeeBps > 10000) revert INVALID_FEES(); - - if (_listingFeeBps > 0) { - _setListingFee(offer, _listingFeeBps, _listingFeeRecipient); - } - - if (_findersFeeBps > 0) { - _setFindersFee(offer, _findersFeeBps); - } - - if (_expiry > 0) { - if (_expiry < block.timestamp) revert INVALID_EXPIRY(); - _setExpiry(offer, _expiry); - } - - emit OfferCreated(_tokenContract, _tokenId, offerCount, _getFullOffer(offer)); - return offerCount; - } - - /// @notice Updates the price of the given offer - /// @param _tokenContract The address of the offer ERC-721 token - /// @param _tokenId The ID of the offer ERC-721 token - /// @param _offerId The ID of the offer - /// @param _offerCurrency The address of the ERC-20 token offered - /// @param _offerAmount The new amount offered - function setOfferAmount( - address _tokenContract, - uint256 _tokenId, - uint256 _offerId, - address _offerCurrency, - uint256 _offerAmount - ) external payable nonReentrant { - StoredOffer storage offer = offers[_tokenContract][_tokenId][_offerId]; - - if (offer.maker != msg.sender) revert CALLER_NOT_MAKER(); - - if (_offerAmount == 0) revert NO_ZERO_OFFERS(); - if (_offerAmount == offer.amount && _offerCurrency == _getERC20CurrencyWithFallback(offer)) revert SAME_OFFER(); - - IERC20 token = IERC20(address(weth)); - if (_offerCurrency != address(0)) { - if (msg.value != 0) revert MSG_VALUE_NEQ_ZERO_WITH_OTHER_CURRENCY(); - token = IERC20(_offerCurrency); - } - if (_offerCurrency == address(0) && msg.value > 0) { - weth.deposit{value: msg.value}(); - weth.transferFrom(address(this), msg.sender, msg.value); - } - if (token.balanceOf(msg.sender) < _offerAmount) revert INSUFFICIENT_BALANCE(); - if (token.allowance(msg.sender, address(erc20TransferHelper)) < _offerAmount) revert INSUFFICIENT_ALLOWANCE(); - - _setETHorERC20Currency(offer, _offerCurrency); - offer.amount = _offerAmount; - - emit OfferUpdated(_tokenContract, _tokenId, _offerId, _getFullOffer(offer)); - } - - /// @notice Cancels the given offer for an NFT - /// @param _tokenContract The ERC-721 token address of the offer - /// @param _tokenId The ERC-721 token ID of the offer - /// @param _offerId The ID of the offer - function cancelOffer( - address _tokenContract, - uint256 _tokenId, - uint256 _offerId - ) external nonReentrant { - if (offers[_tokenContract][_tokenId][_offerId].maker != msg.sender) revert CALLER_NOT_MAKER(); - - emit OfferCanceled(_tokenContract, _tokenId, _offerId, _getFullOffer(offers[_tokenContract][_tokenId][_offerId])); - - // Remove the offer from storage - delete offers[_tokenContract][_tokenId][_offerId]; - } - - function _handleListingAndFindersFees( - uint256 _remainingProfit, - StoredOffer storage offer, - address _currency, - address _finder - ) internal returns (uint256 remainingProfit) { - remainingProfit = _remainingProfit; - uint256 listingFee; - address listingFeeRecipient; - uint256 findersFee; - - if (_hasFeature(offer.features, FEATURE_MASK_LISTING_FEE)) { - uint16 listingFeeBps; - (listingFeeBps, listingFeeRecipient) = _getListingFee(offer); - listingFee = (remainingProfit * listingFeeBps) / 10000; - } - - if (_finder != address(0) && _hasFeature(offer.features, FEATURE_MASK_FINDERS_FEE)) { - findersFee = (remainingProfit * _getFindersFee(offer)) / 10000; - } - - if (listingFee > 0) { - _handleOutgoingTransfer(listingFeeRecipient, listingFee, _currency, 50000); - remainingProfit -= listingFee; - } - if (findersFee > 0) { - _handleOutgoingTransfer(_finder, findersFee, _currency, 50000); - remainingProfit -= findersFee; - } - } - - /// @notice Fills an offer for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _offerId The id of the offer - /// @param _amount The offer amount - /// @param _currency The offer currency - /// @param _finder The offer finder - function fillOffer( - address _tokenContract, - uint256 _tokenId, - uint256 _offerId, - uint256 _amount, - address _currency, - address _finder - ) external nonReentrant { - StoredOffer storage offer = offers[_tokenContract][_tokenId][_offerId]; - - if (offer.maker == address(0)) revert INACTIVE_OFFER(); - if (IERC721(_tokenContract).ownerOf(_tokenId) != msg.sender) revert NOT_TOKEN_OWNER(); - address incomingTransferCurrency = _getERC20CurrencyWithFallback(offer); - - if (incomingTransferCurrency != _currency || offer.amount != _amount) revert INCORRECT_CURRENCY_OR_AMOUNT(); - if (_currency == address(0)) { - incomingTransferCurrency = address(weth); - } - IERC20 token = IERC20(incomingTransferCurrency); - uint256 beforeBalance = token.balanceOf(address(this)); - erc20TransferHelper.safeTransferFrom(incomingTransferCurrency, offer.maker, address(this), _amount); - uint256 afterBalance = token.balanceOf(address(this)); - if (beforeBalance + _amount != afterBalance) revert TOKEN_TRANSFER_AMOUNT_INCORRECT(); - if (_currency == address(0)) { - weth.withdraw(_amount); - } - - if (_hasFeature(offer.features, FEATURE_MASK_EXPIRY)) { - if (_getExpiry(offer) < block.timestamp) revert OFFER_EXPIRED(); - } - - // Payout associated token royalties, if any - (uint256 remainingProfit, ) = _handleRoyaltyPayout(_tokenContract, _tokenId, _amount, _currency, 300000); - - // Payout the module fee, if configured - remainingProfit = _handleProtocolFeePayout(remainingProfit, _currency); - - remainingProfit = _handleListingAndFindersFees(remainingProfit, offer, _currency, _finder); - - // Transfer the remaining profit to the filler - _handleOutgoingTransfer(msg.sender, remainingProfit, _currency, 50000); - - // Transfer the NFT to the buyer - // Reverts if the seller did not approve the ERC721TransferHelper or no longer owns the token - erc721TransferHelper.transferFrom(_tokenContract, msg.sender, offer.maker, _tokenId); - - emit OfferFilled(_tokenContract, _tokenId, _offerId, msg.sender, _finder, _getFullOffer(offer)); - - // Remove the ask from storage - delete offers[_tokenContract][_tokenId][_offerId]; - } - - function getFullOffer( - address _tokenContract, - uint256 _tokenId, - uint256 _offerId - ) external view returns (FullOffer memory) { - return _getFullOffer(offers[_tokenContract][_tokenId][_offerId]); - } - - // This fallback is necessary so the module can call weth.withdraw - fallback() external payable { - require(msg.sender == address(weth)); - } -} diff --git a/contracts/modules/ReserveAuction/Core/ERC20/IReserveAuctionCoreErc20.sol b/contracts/modules/ReserveAuction/Core/ERC20/IReserveAuctionCoreErc20.sol deleted file mode 100644 index 104b6826..00000000 --- a/contracts/modules/ReserveAuction/Core/ERC20/IReserveAuctionCoreErc20.sol +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -/// @title IReserveAuctionCoreErc20 -/// @author kulkarohan -/// @notice Interface for Reserve Auction Core ERC-20 -interface IReserveAuctionCoreErc20 { - /// @notice Creates an auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _duration The length of time the auction should run after the first bid - /// @param _reservePrice The minimum bid amount to start the auction - /// @param _sellerFundsRecipient The address to send funds to once the auction is complete - /// @param _startTime The time that users can begin placing bids - /// @param _bidCurrency The address of the ERC-20 token, or address(0) for ETH, that users must bid with - function createAuction( - address _tokenContract, - uint256 _tokenId, - uint256 _duration, - uint256 _reservePrice, - address _sellerFundsRecipient, - uint256 _startTime, - address _bidCurrency - ) external; - - /// @notice Updates the reserve price for a given auction - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _reservePrice The new reserve price - function setAuctionReservePrice( - address _tokenContract, - uint256 _tokenId, - uint256 _reservePrice - ) external; - - /// @notice Cancels the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function cancelAuction(address _tokenContract, uint256 _tokenId) external; - - /// @notice Places a bid on the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _amount The amount to bid - function createBid( - address _tokenContract, - uint256 _tokenId, - uint256 _amount - ) external payable; - - /// @notice Ends the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function settleAuction(address _tokenContract, uint256 _tokenId) external; -} diff --git a/contracts/modules/ReserveAuction/Core/ERC20/ReserveAuctionCoreErc20.sol b/contracts/modules/ReserveAuction/Core/ERC20/ReserveAuctionCoreErc20.sol deleted file mode 100644 index 17b55227..00000000 --- a/contracts/modules/ReserveAuction/Core/ERC20/ReserveAuctionCoreErc20.sol +++ /dev/null @@ -1,541 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {ReentrancyGuard} from "@rari-capital/solmate/src/utils/ReentrancyGuard.sol"; -import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; - -import {ERC721TransferHelper} from "../../../../transferHelpers/ERC721TransferHelper.sol"; -import {IncomingTransferSupportV1} from "../../../../common/IncomingTransferSupport/V1/IncomingTransferSupportV1.sol"; -import {FeePayoutSupportV1} from "../../../../common/FeePayoutSupport/FeePayoutSupportV1.sol"; -import {ModuleNamingSupportV1} from "../../../../common/ModuleNamingSupport/ModuleNamingSupportV1.sol"; -import {IReserveAuctionCoreErc20} from "./IReserveAuctionCoreErc20.sol"; - -/// @title Reserve Auction Core ERC-20 -/// @author kulkarohan -/// @notice Module for minimal ERC-20 timed reserve auctions for ERC-721 tokens -contract ReserveAuctionCoreErc20 is IReserveAuctionCoreErc20, ReentrancyGuard, IncomingTransferSupportV1, FeePayoutSupportV1, ModuleNamingSupportV1 { - /// /// - /// CONSTANTS /// - /// /// - - /// @notice The minimum amount of time left in an auction after a new bid is created - uint16 constant TIME_BUFFER = 15 minutes; - - /// @notice The minimum percentage difference between two bids - uint8 constant MIN_BID_INCREMENT_PERCENTAGE = 10; - - /// /// - /// IMMUTABLES /// - /// /// - - /// @notice The ZORA ERC-721 Transfer Helper - ERC721TransferHelper public immutable erc721TransferHelper; - - /// /// - /// CONSTRUCTOR /// - /// /// - - /// @param _erc20TransferHelper The ZORA ERC-20 Transfer Helper address - /// @param _erc721TransferHelper The ZORA ERC-721 Transfer Helper address - /// @param _royaltyEngine The Manifold Royalty Engine address - /// @param _protocolFeeSettings The ZORA Protocol Fee Settings address - /// @param _weth The WETH token address - constructor( - address _erc20TransferHelper, - address _erc721TransferHelper, - address _royaltyEngine, - address _protocolFeeSettings, - address _weth - ) - IncomingTransferSupportV1(_erc20TransferHelper) - FeePayoutSupportV1(_royaltyEngine, _protocolFeeSettings, _weth, ERC721TransferHelper(_erc721TransferHelper).ZMM().registrar()) - ModuleNamingSupportV1("Reserve Auction Core ERC-20") - { - erc721TransferHelper = ERC721TransferHelper(_erc721TransferHelper); - } - - /// /// - /// EIP-165 /// - /// /// - - /// @notice Implements EIP-165 for standard interface detection - /// @dev `0x01ffc9a7` is the IERC165 interface id - /// @param _interfaceId The identifier of a given interface - /// @return If the given interface is supported - function supportsInterface(bytes4 _interfaceId) external pure returns (bool) { - return _interfaceId == type(IReserveAuctionCoreErc20).interfaceId || _interfaceId == 0x01ffc9a7; - } - - /// /// - /// AUCTION STORAGE /// - /// /// - - /// @notice The metadata for a given auction - /// @param seller The address of the seller - /// @param sellerFundsRecipient The address where funds are sent after the auction - /// @param reservePrice The reserve price to start the auction - /// @param highestBid The highest bid of the auction - /// @param highestBidder The address of the highest bidder - /// @param duration The length of time that the auction runs after the first bid is placed - /// @param startTime The time that the first bid can be placed - /// @param currency The address of the ERC-20 token, or address(0) for ETH, required to place a bid - /// @param firstBidTime The time that the first bid is placed - struct Auction { - address seller; - address sellerFundsRecipient; - uint256 reservePrice; - uint256 highestBid; - address highestBidder; - uint48 duration; - uint48 startTime; - address currency; - uint96 firstBidTime; - } - - /// @notice The auction for a given NFT, if one exists - /// @dev ERC-721 token contract => ERC-721 token id => Auction - mapping(address => mapping(uint256 => Auction)) public auctionForNFT; - - /// /// - /// CREATE AUCTION /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,-----------------------. - // / \ |ReserveAuctionCoreErc20| - // Caller `-----------+-----------' - // | createAuction() | - // | ------------------------>| - // | | - // | ----. - // | | store auction metadata - // | <---' - // | | - // | ----. - // | | emit AuctionCreated() - // | <---' - // Caller ,-----------+-----------. - // ,-. |ReserveAuctionCoreErc20| - // `-' `-----------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an auction is created - /// @param tokenContract The ERC-721 token address of the created auction - /// @param tokenId The ERC-721 token id of the created auction - /// @param auction The metadata of the created auction - event AuctionCreated(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Creates an auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _duration The length of time the auction should run after the first bid - /// @param _reservePrice The minimum bid amount to start the auction - /// @param _sellerFundsRecipient The address to send funds to once the auction is complete - /// @param _startTime The time that users can begin placing bids - /// @param _bidCurrency The address of the ERC-20 token, or address(0) for ETH, that users must bid with - function createAuction( - address _tokenContract, - uint256 _tokenId, - uint256 _duration, - uint256 _reservePrice, - address _sellerFundsRecipient, - uint256 _startTime, - address _bidCurrency - ) external nonReentrant { - // Get the owner of the specified token - address tokenOwner = IERC721(_tokenContract).ownerOf(_tokenId); - - // Ensure the caller is the owner or an approved operator - require(msg.sender == tokenOwner || IERC721(_tokenContract).isApprovedForAll(tokenOwner, msg.sender), "ONLY_TOKEN_OWNER_OR_OPERATOR"); - - // Ensure the funds recipient is specified - require(_sellerFundsRecipient != address(0), "INVALID_FUNDS_RECIPIENT"); - - // Get the auction's storage pointer - Auction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - // Store the associated metadata - auction.seller = tokenOwner; - auction.sellerFundsRecipient = _sellerFundsRecipient; - auction.reservePrice = _reservePrice; - auction.duration = uint48(_duration); - auction.startTime = uint48(_startTime); - auction.currency = _bidCurrency; - - emit AuctionCreated(_tokenContract, _tokenId, auction); - } - - /// /// - /// UPDATE RESERVE PRICE /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,-----------------------. - // / \ |ReserveAuctionCoreErc20| - // Caller `-----------+-----------' - // | setAuctionReservePrice() | - // | ------------------------>| - // | | - // | ----. - // | | update reserve price - // | <---' - // | | - // | ----. - // | | emit AuctionReservePriceUpdated() - // | <---' - // Caller ,-----------+-----------. - // ,-. |ReserveAuctionCoreErc20| - // `-' `-----------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when a reserve price is updated - /// @param tokenContract The ERC-721 token address of the updated auction - /// @param tokenId The ERC-721 token id of the updated auction - /// @param auction The metadata of the updated auction - event AuctionReservePriceUpdated(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Updates the reserve price for a given auction - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _reservePrice The new reserve price - function setAuctionReservePrice( - address _tokenContract, - uint256 _tokenId, - uint256 _reservePrice - ) external nonReentrant { - // Get the auction for the specified token - Auction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - // Ensure the auction has not started - require(auction.firstBidTime == 0, "AUCTION_STARTED"); - - // Ensure the caller is the seller - require(msg.sender == auction.seller, "ONLY_SELLER"); - - // Update the reserve price - auction.reservePrice = _reservePrice; - - emit AuctionReservePriceUpdated(_tokenContract, _tokenId, auction); - } - - /// /// - /// CANCEL AUCTION /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,-----------------------. - // / \ |ReserveAuctionCoreErc20| - // Caller `-----------+-----------' - // | cancelAuction() | - // | ------------------------>| - // | | - // | ----. - // | | emit AuctionCanceled() - // | <---' - // | | - // | ----. - // | | delete auction - // | <---' - // Caller ,-----------+-----------. - // ,-. |ReserveAuctionCoreErc20| - // `-' `-----------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an auction is canceled - /// @param tokenContract The ERC-721 token address of the canceled auction - /// @param tokenId The ERC-721 token id of the canceled auction - /// @param auction The metadata of the canceled auction - event AuctionCanceled(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Cancels the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function cancelAuction(address _tokenContract, uint256 _tokenId) external nonReentrant { - // Get the auction for the specified token - Auction memory auction = auctionForNFT[_tokenContract][_tokenId]; - - // Ensure the auction has not started - require(auction.firstBidTime == 0, "AUCTION_STARTED"); - - // Ensure the caller is the seller or a new owner of the token - require(msg.sender == auction.seller || msg.sender == IERC721(_tokenContract).ownerOf(_tokenId), "ONLY_SELLER_OR_TOKEN_OWNER"); - - emit AuctionCanceled(_tokenContract, _tokenId, auction); - - // Remove the auction from storage - delete auctionForNFT[_tokenContract][_tokenId]; - } - - /// /// - /// CREATE BID /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,-----------------------. ,--------------------. ,-------------------. - // / \ |ReserveAuctionCoreErc20| |ERC721TransferHelper| |ERC20TransferHelper| - // Caller `-----------+-----------' `---------+----------' `---------+---------' - // | createBid() | | | - // | ------------------------>| | | - // | | | | - // | | | | - // | ___________________________________________________________________________________________________________________________________ - // | ! ALT / First bid? | | | ! - // | !_____/ | | | ! - // | ! ----. | | ! - // | ! | start auction | | ! - // | ! <---' | | ! - // | ! | | | ! - // | ! | transferFrom() | | ! - // | ! |------------------------------->| | ! - // | ! | | | ! - // | ! | |----. ! - // | ! | | | transfer NFT from seller to escrow ! - // | ! | |<---' ! - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | ! [refund previous bidder] | | ! - // | ! | handle outgoing refund | ! - // | ! |----------------------------------------------------------------------->| ! - // | ! | | | ! - // | ! | | |----. ! - // | ! | | | | transfer tokens to bidder ! - // | ! | | |<---' ! - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | | | | - // | | handle incoming bid | - // | |----------------------------------------------------------------------->| - // | | | | - // | | | |----. - // | | | | | transfer tokens to escrow - // | | | |<---' - // | | | | - // | | | | - // | ______________________________________________ | | - // | ! ALT / Bid placed within 15 min of end? ! | | - // | !_____/ | ! | | - // | ! ----. ! | | - // | ! | extend auction ! | | - // | ! <---' ! | | - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! | | - // | !~[noop]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! | | - // | | | | - // | ----. | | - // | | emit AuctionBid() | | - // | <---' | | - // Caller ,-----------+-----------. ,---------+----------. ,---------+---------. - // ,-. |ReserveAuctionCoreErc20| |ERC721TransferHelper| |ERC20TransferHelper| - // `-' `-----------------------' `--------------------' `-------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when a bid is placed - /// @param tokenContract The ERC-721 token address of the auction - /// @param tokenId The ERC-721 token id of the auction - /// @param firstBid If the bid started the auction - /// @param extended If the bid extended the auction - /// @param auction The metadata of the auction - event AuctionBid(address indexed tokenContract, uint256 indexed tokenId, bool firstBid, bool extended, Auction auction); - - /// @notice Places a bid on the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _amount The amount to bid - function createBid( - address _tokenContract, - uint256 _tokenId, - uint256 _amount - ) external payable nonReentrant { - // Get the auction for the specified token - Auction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - // Cache the seller - address seller = auction.seller; - - // Ensure the auction exists - require(seller != address(0), "AUCTION_DOES_NOT_EXIST"); - - // Ensure the auction has started or is valid to start - require(block.timestamp >= auction.startTime, "AUCTION_NOT_STARTED"); - - // Cache more auction metadata - uint256 firstBidTime = auction.firstBidTime; - uint256 duration = auction.duration; - address currency = auction.currency; - - // Used to emit whether the bid started the auction - bool firstBid; - - // If this is the first bid, start the auction - if (firstBidTime == 0) { - // Ensure the bid meets the reserve price - require(_amount >= auction.reservePrice, "RESERVE_PRICE_NOT_MET"); - - // Store the current time as the first bid time - auction.firstBidTime = uint96(block.timestamp); - - // Mark this bid as the first - firstBid = true; - - // Transfer the NFT from the seller into escrow for the duration of the auction - // Reverts if the seller did not approve the ERC721TransferHelper or no longer owns the token - erc721TransferHelper.transferFrom(_tokenContract, seller, address(this), _tokenId); - - // Else this is a subsequent bid, so refund the previous bidder - } else { - // Ensure the auction has not ended - require(block.timestamp < firstBidTime + duration, "AUCTION_OVER"); - - // Cache the highest bid - uint256 highestBid = auction.highestBid; - - // Used to store the minimum bid required to outbid the highest bidder - uint256 minValidBid; - - // Calculate the minimum bid required (10% higher than the highest bid) - minValidBid = highestBid + ((highestBid * MIN_BID_INCREMENT_PERCENTAGE) / 100); - - // Ensure the incoming bid meets the minimum - require(_amount >= minValidBid, "MINIMUM_BID_NOT_MET"); - - // Refund the previous bidder - _handleOutgoingTransfer(auction.highestBidder, highestBid, currency, 50000); - } - - // Retrieve the bid from the bidder - // If ETH, this reverts if the bidder did not attach enough - // If ERC-20, this reverts if the bidder did not approve the ERC20TransferHelper or does not own the specified amount - _handleIncomingTransfer(_amount, currency); - - // Store the amount as the highest bid - auction.highestBid = _amount; - - // Store the caller as the highest bidder - auction.highestBidder = msg.sender; - - // Used to emit whether the bid extended the auction - bool extended; - - // Used to store the auction time remaining - uint256 timeRemaining; - - // Get the auction time remaining - // Cannot underflow as `firstBidTime + duration` is ensured to be greater than `block.timestamp` - unchecked { - timeRemaining = firstBidTime + duration - block.timestamp; - } - - // If the bid is placed within 15 minutes of the auction end, extend the auction - if (timeRemaining < TIME_BUFFER) { - // Add (15 minutes - remaining time) to the duration so that 15 minutes remain - // Cannot underflow as `timeRemaining` is ensured to be less than `TIME_BUFFER` - unchecked { - auction.duration += uint48(TIME_BUFFER - timeRemaining); - } - - // Mark the bid as one that extended the auction - extended = true; - } - - emit AuctionBid(_tokenContract, _tokenId, firstBid, extended, auction); - } - - /// /// - /// SETTLE AUCTION /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,-----------------------. - // / \ |ReserveAuctionCoreErc20| - // Caller `-----------+-----------' - // | settleAuction() | - // | ------------------------>| - // | | - // | ----. - // | | validate auction ended - // | <---' - // | | - // | ----. - // | | handle royalty payouts - // | <---' - // | | - // | ----. - // | | handle seller funds recipient payout - // | <---' - // | | - // | ----. - // | | transfer NFT from escrow to winning bidder - // | <---' - // | | - // | ----. - // | | emit AuctionEnded() - // | <---' - // | | - // | ----. - // | | delete auction from contract - // | <---' - // Caller ,-----------+-----------. - // ,-. |ReserveAuctionCoreErc20| - // `-' `-----------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an auction has ended - /// @param tokenContract The ERC-721 token address of the auction - /// @param tokenId The ERC-721 token id of the auction - /// @param auction The metadata of the settled auction - event AuctionEnded(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Ends the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function settleAuction(address _tokenContract, uint256 _tokenId) external nonReentrant { - // Get the auction for the specified token - Auction memory auction = auctionForNFT[_tokenContract][_tokenId]; - - // Cache the time of the first bid - uint256 firstBidTime = auction.firstBidTime; - - // Ensure the auction had started - require(firstBidTime != 0, "AUCTION_NOT_STARTED"); - - // Ensure the auction has ended - require(block.timestamp >= (firstBidTime + auction.duration), "AUCTION_NOT_OVER"); - - // Cache the auction currency - address currency = auction.currency; - - // Payout associated token royalties, if any - (uint256 remainingProfit, ) = _handleRoyaltyPayout(_tokenContract, _tokenId, auction.highestBid, currency, 300000); - - // Payout the module fee, if configured by the owner - remainingProfit = _handleProtocolFeePayout(remainingProfit, currency); - - // Transfer the remaining profit to the funds recipient - _handleOutgoingTransfer(auction.sellerFundsRecipient, remainingProfit, currency, 50000); - - // Transfer the NFT to the winning bidder - IERC721(_tokenContract).transferFrom(address(this), auction.highestBidder, _tokenId); - - emit AuctionEnded(_tokenContract, _tokenId, auction); - - // Remove the auction from storage - delete auctionForNFT[_tokenContract][_tokenId]; - } -} diff --git a/contracts/modules/ReserveAuction/Core/ETH/IReserveAuctionCoreEth.sol b/contracts/modules/ReserveAuction/Core/ETH/IReserveAuctionCoreEth.sol deleted file mode 100644 index b85387a5..00000000 --- a/contracts/modules/ReserveAuction/Core/ETH/IReserveAuctionCoreEth.sol +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -/// @title IReserveAuctionCoreEth -/// @author kulkarohan -/// @notice Interface for Reserve Auction Core ETH -interface IReserveAuctionCoreEth { - /// @notice Creates an auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _duration The length of time the auction should run after the first bid - /// @param _reservePrice The minimum bid amount to start the auction - /// @param _sellerFundsRecipient The address to send funds to once the auction is complete - /// @param _startTime The time that users can begin placing bids - function createAuction( - address _tokenContract, - uint256 _tokenId, - uint256 _duration, - uint256 _reservePrice, - address _sellerFundsRecipient, - uint256 _startTime - ) external; - - /// @notice Updates the auction reserve price for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _reservePrice The new reserve price - function setAuctionReservePrice( - address _tokenContract, - uint256 _tokenId, - uint256 _reservePrice - ) external; - - /// @notice Cancels the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function cancelAuction(address _tokenContract, uint256 _tokenId) external; - - /// @notice Places a bid on the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function createBid(address _tokenContract, uint256 _tokenId) external payable; - - /// @notice Ends the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function settleAuction(address _tokenContract, uint256 _tokenId) external; -} diff --git a/contracts/modules/ReserveAuction/Core/ETH/ReserveAuctionCoreEth.sol b/contracts/modules/ReserveAuction/Core/ETH/ReserveAuctionCoreEth.sol deleted file mode 100644 index 0c5d38f2..00000000 --- a/contracts/modules/ReserveAuction/Core/ETH/ReserveAuctionCoreEth.sol +++ /dev/null @@ -1,511 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {ReentrancyGuard} from "@rari-capital/solmate/src/utils/ReentrancyGuard.sol"; -import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; - -import {ERC721TransferHelper} from "../../../../transferHelpers/ERC721TransferHelper.sol"; -import {FeePayoutSupportV1} from "../../../../common/FeePayoutSupport/FeePayoutSupportV1.sol"; -import {ModuleNamingSupportV1} from "../../../../common/ModuleNamingSupport/ModuleNamingSupportV1.sol"; -import {IReserveAuctionCoreEth} from "./IReserveAuctionCoreEth.sol"; - -/// @title Reserve Auction Core ETH -/// @author kulkarohan -/// @notice Module for minimal ETH timed reserve auctions for ERC-721 tokens -contract ReserveAuctionCoreEth is IReserveAuctionCoreEth, ReentrancyGuard, FeePayoutSupportV1, ModuleNamingSupportV1 { - /// /// - /// CONSTANTS /// - /// /// - - /// @notice The minimum amount of time left in an auction after a new bid is created - uint16 constant TIME_BUFFER = 15 minutes; - - /// @notice The minimum percentage difference between two bids - uint8 constant MIN_BID_INCREMENT_PERCENTAGE = 10; - - /// /// - /// IMMUTABLES /// - /// /// - - /// @notice The ZORA ERC-721 Transfer Helper - ERC721TransferHelper public immutable erc721TransferHelper; - - /// /// - /// CONSTRUCTOR /// - /// /// - - /// @param _erc721TransferHelper The ZORA ERC-721 Transfer Helper address - /// @param _royaltyEngine The Manifold Royalty Engine address - /// @param _protocolFeeSettings The ZORA Protocol Fee Settings address - /// @param _weth The WETH token address - constructor( - address _erc721TransferHelper, - address _royaltyEngine, - address _protocolFeeSettings, - address _weth - ) - FeePayoutSupportV1(_royaltyEngine, _protocolFeeSettings, _weth, ERC721TransferHelper(_erc721TransferHelper).ZMM().registrar()) - ModuleNamingSupportV1("Reserve Auction Core ETH") - { - erc721TransferHelper = ERC721TransferHelper(_erc721TransferHelper); - } - - /// /// - /// EIP-165 /// - /// /// - - /// @notice Implements EIP-165 for standard interface detection - /// @dev `0x01ffc9a7` is the IERC165 interface id - /// @param _interfaceId The identifier of a given interface - /// @return If the given interface is supported - function supportsInterface(bytes4 _interfaceId) external pure returns (bool) { - return _interfaceId == type(IReserveAuctionCoreEth).interfaceId || _interfaceId == 0x01ffc9a7; - } - - /// /// - /// AUCTION STORAGE /// - /// /// - - /// @notice The metadata for a given auction - /// @param seller The address of the seller - /// @param reservePrice The reserve price to start the auction - /// @param sellerFundsRecipient The address where funds are sent after the auction - /// @param highestBid The highest bid of the auction - /// @param highestBidder The address of the highest bidder - /// @param duration The length of time that the auction runs after the first bid is placed - /// @param startTime The time that the first bid can be placed - /// @param firstBidTime The time that the first bid is placed - struct Auction { - address seller; - uint96 reservePrice; - address sellerFundsRecipient; - uint96 highestBid; - address highestBidder; - uint32 duration; - uint32 startTime; - uint32 firstBidTime; - } - - /// @notice The auction for a given NFT, if one exists - /// @dev ERC-721 token contract => ERC-721 token id => Auction - mapping(address => mapping(uint256 => Auction)) public auctionForNFT; - - /// /// - /// CREATE AUCTION /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,---------------------. - // / \ |ReserveAuctionCoreEth| - // Caller `----------+----------' - // | createAuction() | - // | ----------------------->| - // | | - // | ----. - // | | store auction metadata - // | <---' - // | | - // | ----. - // | | emit AuctionCreated() - // | <---' - // Caller ,----------+----------. - // ,-. |ReserveAuctionCoreEth| - // `-' `---------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an auction is created - /// @param tokenContract The ERC-721 token address of the created auction - /// @param tokenId The ERC-721 token id of the created auction - /// @param auction The metadata of the created auction - event AuctionCreated(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Creates an auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _duration The length of time the auction should run after the first bid - /// @param _reservePrice The minimum bid amount to start the auction - /// @param _sellerFundsRecipient The address to send funds to once the auction is complete - /// @param _startTime The time that users can begin placing bids - function createAuction( - address _tokenContract, - uint256 _tokenId, - uint256 _duration, - uint256 _reservePrice, - address _sellerFundsRecipient, - uint256 _startTime - ) external nonReentrant { - // Get the owner of the specified token - address tokenOwner = IERC721(_tokenContract).ownerOf(_tokenId); - - // Ensure the caller is the owner or an approved operator - require(msg.sender == tokenOwner || IERC721(_tokenContract).isApprovedForAll(tokenOwner, msg.sender), "ONLY_TOKEN_OWNER_OR_OPERATOR"); - - // Ensure the funds recipient is specified - require(_sellerFundsRecipient != address(0), "INVALID_FUNDS_RECIPIENT"); - - // Get the auction's storage pointer - Auction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - // Store the associated metadata - auction.seller = tokenOwner; - auction.reservePrice = uint96(_reservePrice); - auction.sellerFundsRecipient = _sellerFundsRecipient; - auction.duration = uint32(_duration); - auction.startTime = uint32(_startTime); - - emit AuctionCreated(_tokenContract, _tokenId, auction); - } - - /// /// - /// UPDATE RESERVE PRICE /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,---------------------. - // / \ |ReserveAuctionCoreEth| - // Caller `----------+----------' - // | setAuctionReservePrice()| - // | ------------------------> - // | | - // | |----. - // | | | update reserve price - // | |<---' - // | | - // | |----. - // | | | emit AuctionReservePriceUpdated() - // | |<---' - // Caller ,----------+----------. - // ,-. |ReserveAuctionCoreEth| - // `-' `---------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when a reserve price is updated - /// @param tokenContract The ERC-721 token address of the updated auction - /// @param tokenId The ERC-721 token id of the updated auction - /// @param auction The metadata of the updated auction - event AuctionReservePriceUpdated(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Updates the auction reserve price for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _reservePrice The new reserve price - function setAuctionReservePrice( - address _tokenContract, - uint256 _tokenId, - uint256 _reservePrice - ) external nonReentrant { - // Get the auction for the specified token - Auction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - // Ensure the auction has not started - require(auction.firstBidTime == 0, "AUCTION_STARTED"); - - // Ensure the caller is the seller - require(msg.sender == auction.seller, "ONLY_SELLER"); - - // Update the reserve price - auction.reservePrice = uint96(_reservePrice); - - emit AuctionReservePriceUpdated(_tokenContract, _tokenId, auction); - } - - /// /// - /// CANCEL AUCTION /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,---------------------. - // / \ |ReserveAuctionCoreEth| - // Caller `----------+----------' - // | cancelAuction() | - // | ----------------------->| - // | | - // | ----. - // | | emit AuctionCanceled() - // | <---' - // | | - // | ----. - // | | delete auction - // | <---' - // Caller ,----------+----------. - // ,-. |ReserveAuctionCoreEth| - // `-' `---------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an auction is canceled - /// @param tokenContract The ERC-721 token address of the canceled auction - /// @param tokenId The ERC-721 token id of the canceled auction - /// @param auction The metadata of the canceled auction - event AuctionCanceled(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Cancels the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function cancelAuction(address _tokenContract, uint256 _tokenId) external nonReentrant { - // Get the auction for the specified token - Auction memory auction = auctionForNFT[_tokenContract][_tokenId]; - - // Ensure the auction has not started - require(auction.firstBidTime == 0, "AUCTION_STARTED"); - - // Ensure the caller is the seller or a new owner - require(msg.sender == auction.seller || msg.sender == IERC721(_tokenContract).ownerOf(_tokenId), "ONLY_SELLER_OR_TOKEN_OWNER"); - - emit AuctionCanceled(_tokenContract, _tokenId, auction); - - // Remove the auction from storage - delete auctionForNFT[_tokenContract][_tokenId]; - } - - /// /// - /// CREATE BID /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,---------------------. ,--------------------. - // / \ |ReserveAuctionCoreEth| |ERC721TransferHelper| - // Caller `----------+----------' `---------+----------' - // | createBid() | | - // | ----------------------->| | - // | | | - // | | | - // | __________________________________________________________________________________________________ - // | ! ALT / First bid? | | ! - // | !_____/ | | ! - // | ! ----. | ! - // | ! | start auction | ! - // | ! <---' | ! - // | ! | | ! - // | ! | transferFrom() | ! - // | ! |------------------------------>| ! - // | ! | | ! - // | ! | |----. ! - // | ! | | | transfer NFT from seller to escrow ! - // | ! | |<---' ! - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | ! [refund previous bidder] | ! - // | ! ----. | ! - // | ! | transfer ETH to bidder | ! - // | ! <---' | ! - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | | | - // | | | - // | _____________________________________________ | - // | ! ALT / Bid placed within 15 min of end? ! | - // | !_____/ | ! | - // | ! ----. ! | - // | ! | extend auction ! | - // | ! <---' ! | - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! | - // | !~[noop]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! | - // | | | - // | ----. | - // | | emit AuctionBid() | - // | <---' | - // Caller ,----------+----------. ,---------+----------. - // ,-. |ReserveAuctionCoreEth| |ERC721TransferHelper| - // `-' `---------------------' `--------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when a bid is placed - /// @param tokenContract The ERC-721 token address of the auction - /// @param tokenId The ERC-721 token id of the auction - /// @param firstBid If the bid started the auction - /// @param extended If the bid extended the auction - /// @param auction The metadata of the auction - event AuctionBid(address indexed tokenContract, uint256 indexed tokenId, bool firstBid, bool extended, Auction auction); - - /// @notice Places a bid on the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function createBid(address _tokenContract, uint256 _tokenId) external payable nonReentrant { - // Get the auction for the specified token - Auction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - // Cache the seller - address seller = auction.seller; - - // Ensure the auction exists - require(seller != address(0), "AUCTION_DOES_NOT_EXIST"); - - // Ensure the auction has started or is valid to start - require(block.timestamp >= auction.startTime, "AUCTION_NOT_STARTED"); - - // Cache more auction metadata - uint256 firstBidTime = auction.firstBidTime; - uint256 duration = auction.duration; - - // Used to emit whether the bid started the auction - bool firstBid; - - // If this is the first bid, start the auction - if (firstBidTime == 0) { - // Ensure the bid meets the reserve price - require(msg.value >= auction.reservePrice, "RESERVE_PRICE_NOT_MET"); - - // Store the current time as the first bid time - auction.firstBidTime = uint32(block.timestamp); - - // Mark the bid as the first - firstBid = true; - - // Transfer the NFT from the seller into escrow for the duration of the auction - // Reverts if the seller did not approve the ERC721TransferHelper or no longer owns the token - erc721TransferHelper.transferFrom(_tokenContract, seller, address(this), _tokenId); - - // Else this is a subsequent bid, so refund the previous bidder - } else { - // Ensure the auction has not ended - require(block.timestamp < (firstBidTime + duration), "AUCTION_OVER"); - - // Cache the highest bid - uint256 highestBid = auction.highestBid; - - // Used to store the minimum bid required to outbid the highest bidder - uint256 minValidBid; - - // Calculate the minimum bid required (10% higher than the highest bid) - // Cannot overflow as the highest bid would have to be magnitudes higher than the total supply of ETH - unchecked { - minValidBid = highestBid + ((highestBid * MIN_BID_INCREMENT_PERCENTAGE) / 100); - } - - // Ensure the incoming bid meets the minimum - require(msg.value >= minValidBid, "MINIMUM_BID_NOT_MET"); - - // Refund the previous bidder - _handleOutgoingTransfer(auction.highestBidder, highestBid, address(0), 50000); - } - - // Store the attached ETH as the highest bid - auction.highestBid = uint96(msg.value); - - // Store the caller as the highest bidder - auction.highestBidder = msg.sender; - - // Used to emit whether the bid extended the auction - bool extended; - - // Used to store the auction time remaining - uint256 timeRemaining; - - // Get the auction time remaining - // Cannot underflow as `firstBidTime + duration` is ensured to be greater than `block.timestamp` - unchecked { - timeRemaining = firstBidTime + duration - block.timestamp; - } - - // If the bid is placed within 15 minutes of the auction end, extend the auction - if (timeRemaining < TIME_BUFFER) { - // Add (15 minutes - remaining time) to the duration so that 15 minutes remain - // Cannot underflow as `timeRemaining` is ensured to be less than `TIME_BUFFER` - unchecked { - auction.duration += uint32(TIME_BUFFER - timeRemaining); - } - - // Mark the bid as one that extended the auction - extended = true; - } - - emit AuctionBid(_tokenContract, _tokenId, firstBid, extended, auction); - } - - /// /// - /// SETTLE AUCTION /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,---------------------. - // / \ |ReserveAuctionCoreEth| - // Caller `----------+----------' - // | settleAuction() | - // | ----------------------->| - // | | - // | ----. - // | | validate auction ended - // | <---' - // | | - // | ----. - // | | handle royalty payouts - // | <---' - // | | - // | ----. - // | | handle seller funds recipient payout - // | <---' - // | | - // | ----. - // | | transfer NFT from escrow to winning bidder - // | <---' - // | | - // | ----. - // | | emit AuctionEnded() - // | <---' - // | | - // | ----. - // | | delete auction from contract - // | <---' - // Caller ,----------+----------. - // ,-. |ReserveAuctionCoreEth| - // `-' `---------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an auction has ended - /// @param tokenContract The ERC-721 token address of the auction - /// @param tokenId The ERC-721 token id of the auction - /// @param auction The metadata of the settled auction - event AuctionEnded(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Ends the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function settleAuction(address _tokenContract, uint256 _tokenId) external nonReentrant { - // Get the auction for the specified token - Auction memory auction = auctionForNFT[_tokenContract][_tokenId]; - - // Cache the time of the first bid - uint256 firstBidTime = auction.firstBidTime; - - // Ensure the auction had started - require(firstBidTime != 0, "AUCTION_NOT_STARTED"); - - // Ensure the auction has ended - require(block.timestamp >= (firstBidTime + auction.duration), "AUCTION_NOT_OVER"); - - // Payout associated token royalties, if any - (uint256 remainingProfit, ) = _handleRoyaltyPayout(_tokenContract, _tokenId, auction.highestBid, address(0), 300000); - - // Payout the module fee, if configured by the owner - remainingProfit = _handleProtocolFeePayout(remainingProfit, address(0)); - - // Transfer the remaining profit to the funds recipient - _handleOutgoingTransfer(auction.sellerFundsRecipient, remainingProfit, address(0), 50000); - - // Transfer the NFT to the winning bidder - IERC721(_tokenContract).transferFrom(address(this), auction.highestBidder, _tokenId); - - emit AuctionEnded(_tokenContract, _tokenId, auction); - - // Remove the auction from storage - delete auctionForNFT[_tokenContract][_tokenId]; - } -} diff --git a/contracts/modules/ReserveAuction/Finders/ERC20/IReserveAuctionFindersErc20.sol b/contracts/modules/ReserveAuction/Finders/ERC20/IReserveAuctionFindersErc20.sol deleted file mode 100644 index 9f057aff..00000000 --- a/contracts/modules/ReserveAuction/Finders/ERC20/IReserveAuctionFindersErc20.sol +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -/// @title IReserveAuctionFindersErc20 -/// @author kulkarohan -/// @notice Interface for Reserve Auction Finders ERC-20 -interface IReserveAuctionFindersErc20 { - /// @notice Creates an auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _duration The length of time the auction should run after the first bid - /// @param _reservePrice The minimum bid amount to start the auction - /// @param _sellerFundsRecipient The address to send funds to once the auction is complete - /// @param _startTime The time that users can begin placing bids - /// @param _bidCurrency The address of the ERC-20 token, or address(0) for ETH, that users must bid with - /// @param _findersFeeBps The fee to send to the referrer of the winning bid - function createAuction( - address _tokenContract, - uint256 _tokenId, - uint256 _duration, - uint256 _reservePrice, - address _sellerFundsRecipient, - uint256 _startTime, - address _bidCurrency, - uint256 _findersFeeBps - ) external; - - /// @notice Updates the reserve price for a given auction - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _reservePrice The new reserve price - function setAuctionReservePrice( - address _tokenContract, - uint256 _tokenId, - uint256 _reservePrice - ) external; - - /// @notice Cancels the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function cancelAuction(address _tokenContract, uint256 _tokenId) external; - - /// @notice Places a bid on the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _amount The amount to bid - /// @param _finder The referrer of the bid - function createBid( - address _tokenContract, - uint256 _tokenId, - uint256 _amount, - address _finder - ) external payable; - - /// @notice Ends the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function settleAuction(address _tokenContract, uint256 _tokenId) external; -} diff --git a/contracts/modules/ReserveAuction/Finders/ERC20/ReserveAuctionFindersErc20.sol b/contracts/modules/ReserveAuction/Finders/ERC20/ReserveAuctionFindersErc20.sol deleted file mode 100644 index bf1131d7..00000000 --- a/contracts/modules/ReserveAuction/Finders/ERC20/ReserveAuctionFindersErc20.sol +++ /dev/null @@ -1,587 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {ReentrancyGuard} from "@rari-capital/solmate/src/utils/ReentrancyGuard.sol"; -import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; - -import {ERC721TransferHelper} from "../../../../transferHelpers/ERC721TransferHelper.sol"; -import {IncomingTransferSupportV1} from "../../../../common/IncomingTransferSupport/V1/IncomingTransferSupportV1.sol"; -import {FeePayoutSupportV1} from "../../../../common/FeePayoutSupport/FeePayoutSupportV1.sol"; -import {ModuleNamingSupportV1} from "../../../../common/ModuleNamingSupport/ModuleNamingSupportV1.sol"; -import {IReserveAuctionFindersErc20} from "./IReserveAuctionFindersErc20.sol"; - -/// @title Reserve Auction Finders ERC-20 -/// @author kulkarohan -/// @notice Module adding Finders Fee to Reserve Auction Core ERC-20 -contract ReserveAuctionFindersErc20 is - IReserveAuctionFindersErc20, - ReentrancyGuard, - IncomingTransferSupportV1, - FeePayoutSupportV1, - ModuleNamingSupportV1 -{ - /// /// - /// CONSTANTS /// - /// /// - - /// @notice The minimum amount of time left in an auction after a new bid is created - uint16 constant TIME_BUFFER = 15 minutes; - - /// @notice The minimum percentage difference between two bids - uint8 constant MIN_BID_INCREMENT_PERCENTAGE = 10; - - /// /// - /// IMMUTABLES /// - /// /// - - /// @notice The ZORA ERC-721 Transfer Helper - ERC721TransferHelper public immutable erc721TransferHelper; - - /// /// - /// CONSTRUCTOR /// - /// /// - - /// @param _erc20TransferHelper The ZORA ERC-20 Transfer Helper address - /// @param _erc721TransferHelper The ZORA ERC-721 Transfer Helper address - /// @param _royaltyEngine The Manifold Royalty Engine address - /// @param _protocolFeeSettings The ZORA Protocol Fee Settings address - /// @param _weth The WETH token address - constructor( - address _erc20TransferHelper, - address _erc721TransferHelper, - address _royaltyEngine, - address _protocolFeeSettings, - address _weth - ) - IncomingTransferSupportV1(_erc20TransferHelper) - FeePayoutSupportV1(_royaltyEngine, _protocolFeeSettings, _weth, ERC721TransferHelper(_erc721TransferHelper).ZMM().registrar()) - ModuleNamingSupportV1("Reserve Auction Finders ERC-20") - { - erc721TransferHelper = ERC721TransferHelper(_erc721TransferHelper); - } - - /// /// - /// EIP-165 /// - /// /// - - /// @notice Implements EIP-165 for standard interface detection - /// @dev `0x01ffc9a7` is the IERC165 interface id - /// @param _interfaceId The identifier of a given interface - /// @return If the given interface is supported - function supportsInterface(bytes4 _interfaceId) external pure returns (bool) { - return _interfaceId == type(IReserveAuctionFindersErc20).interfaceId || _interfaceId == 0x01ffc9a7; - } - - /// /// - /// AUCTION STORAGE /// - /// /// - - /// @notice The metadata for a given auction - /// @param seller The address of the seller - /// @param sellerFundsRecipient The address where funds are sent after the auction - /// @param reservePrice The reserve price to start the auction - /// @param highestBid The highest bid of the auction - /// @param highestBidder The address of the highest bidder - /// @param startTime The time that the first bid can be placed - /// @param currency The address of the ERC-20 token, or address(0) for ETH, required to place a bid - /// @param firstBidTime The time that the first bid is placed - /// @param finder The address that referred the highest bid - /// @param duration The length of time that the auction runs after the first bid is placed - /// @param findersFeeBps The fee that is sent to the referrer of the highest bid - struct Auction { - address seller; - address sellerFundsRecipient; - uint256 reservePrice; - uint256 highestBid; - address highestBidder; - uint96 startTime; - address currency; - uint96 firstBidTime; - address finder; - uint80 duration; - uint16 findersFeeBps; - } - - /// @notice The auction for a given NFT, if one exists - /// @dev ERC-721 token contract => ERC-721 token id => Auction - mapping(address => mapping(uint256 => Auction)) public auctionForNFT; - - /// /// - /// CREATE AUCTION /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,--------------------------. - // / \ |ReserveAuctionFindersErc20| - // Caller `------------+-------------' - // | createAuction() | - // | --------------------------> - // | | - // | |----. - // | | | store auction metadata - // | |<---' - // | | - // | |----. - // | | | emit AuctionCreated() - // | |<---' - // Caller ,------------+-------------. - // ,-. |ReserveAuctionFindersErc20| - // `-' `--------------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an auction is created - /// @param tokenContract The ERC-721 token address of the created auction - /// @param tokenId The ERC-721 token id of the created auction - /// @param auction The metadata of the created auction - event AuctionCreated(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Creates an auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _duration The length of time the auction should run after the first bid - /// @param _reservePrice The minimum bid amount to start the auction - /// @param _sellerFundsRecipient The address to send funds to once the auction is complete - /// @param _startTime The time that users can begin placing bids - /// @param _bidCurrency The address of the ERC-20 token, or address(0) for ETH, that users must bid with - /// @param _findersFeeBps The fee to send to the referrer of the winning bid - function createAuction( - address _tokenContract, - uint256 _tokenId, - uint256 _duration, - uint256 _reservePrice, - address _sellerFundsRecipient, - uint256 _startTime, - address _bidCurrency, - uint256 _findersFeeBps - ) external nonReentrant { - // Get the owner of the specified token - address tokenOwner = IERC721(_tokenContract).ownerOf(_tokenId); - - // Ensure the caller is the owner or an approved operator - require(msg.sender == tokenOwner || IERC721(_tokenContract).isApprovedForAll(tokenOwner, msg.sender), "ONLY_TOKEN_OWNER_OR_OPERATOR"); - - // Ensure the funds recipient is specified - require(_sellerFundsRecipient != address(0), "INVALID_FUNDS_RECIPIENT"); - - // Ensure the finders fee does not exceed 10,000 basis points - require(_findersFeeBps <= 10000, "INVALID_FINDERS_FEE"); - - // Get the auction's storage pointer - Auction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - // Store the associated metadata - auction.seller = tokenOwner; - auction.sellerFundsRecipient = _sellerFundsRecipient; - auction.reservePrice = _reservePrice; - auction.startTime = uint96(_startTime); - auction.currency = _bidCurrency; - auction.duration = uint80(_duration); - auction.findersFeeBps = uint16(_findersFeeBps); - - emit AuctionCreated(_tokenContract, _tokenId, auction); - } - - /// /// - /// UPDATE RESERVE PRICE /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,--------------------------. - // / \ |ReserveAuctionFindersErc20| - // Caller `------------+-------------' - // | setAuctionReservePrice() | - // | --------------------------> - // | | - // | |----. - // | | | update reserve price - // | |<---' - // | | - // | |----. - // | | | emit AuctionReservePriceUpdated() - // | |<---' - // Caller ,------------+-------------. - // ,-. |ReserveAuctionFindersErc20| - // `-' `--------------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when a reserve price is updated - /// @param tokenContract The ERC-721 token address of the updated auction - /// @param tokenId The ERC-721 token id of the updated auction - /// @param auction The metadata of the updated auction - event AuctionReservePriceUpdated(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Updates the reserve price for a given auction - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _reservePrice The new reserve price - function setAuctionReservePrice( - address _tokenContract, - uint256 _tokenId, - uint256 _reservePrice - ) external nonReentrant { - // Get the auction for the specified token - Auction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - // Ensure the auction has not started - require(auction.firstBidTime == 0, "AUCTION_STARTED"); - - // Ensure the caller is the seller - require(msg.sender == auction.seller, "ONLY_SELLER"); - - // Update the reserve price - auction.reservePrice = _reservePrice; - - emit AuctionReservePriceUpdated(_tokenContract, _tokenId, auction); - } - - /// /// - /// CANCEL AUCTION /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,--------------------------. - // / \ |ReserveAuctionFindersErc20| - // Caller `------------+-------------' - // | cancelAuction() | - // | --------------------------> - // | | - // | |----. - // | | | emit AuctionCanceled() - // | |<---' - // | | - // | |----. - // | | | delete auction - // | |<---' - // Caller ,------------+-------------. - // ,-. |ReserveAuctionFindersErc20| - // `-' `--------------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an auction is canceled - /// @param tokenContract The ERC-721 token address of the canceled auction - /// @param tokenId The ERC-721 token id of the canceled auction - /// @param auction The metadata of the canceled auction - event AuctionCanceled(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Cancels the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function cancelAuction(address _tokenContract, uint256 _tokenId) external nonReentrant { - // Get the auction for the specified token - Auction memory auction = auctionForNFT[_tokenContract][_tokenId]; - - // Ensure the auction has not started - require(auction.firstBidTime == 0, "AUCTION_STARTED"); - - // Ensure the caller is the seller or a new owner of the token - require(msg.sender == auction.seller || msg.sender == IERC721(_tokenContract).ownerOf(_tokenId), "ONLY_SELLER_OR_TOKEN_OWNER"); - - emit AuctionCanceled(_tokenContract, _tokenId, auction); - - // Remove the auction from storage - delete auctionForNFT[_tokenContract][_tokenId]; - } - - /// /// - /// CREATE BID /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,--------------------------. ,--------------------. ,-------------------. - // / \ |ReserveAuctionFindersErc20| |ERC721TransferHelper| |ERC20TransferHelper| - // Caller `------------+-------------' `---------+----------' `---------+---------' - // | createBid() | | | - // | --------------------------> | | - // | | | | - // | | | | - // | ______________________________________________________________________________________________________________________________________ - // | ! ALT / First bid? | | | ! - // | !_____/ | | | ! - // | ! |----. | | ! - // | ! | | start auction | | ! - // | ! |<---' | | ! - // | ! | | | ! - // | ! | transferFrom() | | ! - // | ! | ---------------------------------> | ! - // | ! | | | ! - // | ! | |----. ! - // | ! | | | transfer NFT from seller to escrow ! - // | ! | |<---' ! - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | ! [refund previous bidder] | | ! - // | ! | handle outgoing refund | ! - // | ! | -------------------------------------------------------------------------> ! - // | ! | | | ! - // | ! | | |----. ! - // | ! | | | | transfer tokens to bidder ! - // | ! | | |<---' ! - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | | | | - // | | handle incoming bid | - // | | -------------------------------------------------------------------------> - // | | | | - // | | | |----. - // | | | | | transfer tokens to escrow - // | | | |<---' - // | | | | - // | | | | - // | ________________________________________________ | | - // | ! ALT / Bid placed within 15 min of end? ! | | - // | !_____/ | ! | | - // | ! |----. ! | | - // | ! | | extend auction ! | | - // | ! |<---' ! | | - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! | | - // | !~[noop]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! | | - // | | | | - // | |----. | | - // | | | emit AuctionBid() | | - // | |<---' | | - // Caller ,------------+-------------. ,---------+----------. ,---------+---------. - // ,-. |ReserveAuctionFindersErc20| |ERC721TransferHelper| |ERC20TransferHelper| - // `-' `--------------------------' `--------------------' `-------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when a bid is placed - /// @param tokenContract The ERC-721 token address of the auction - /// @param tokenId The ERC-721 token id of the auction - /// @param firstBid If the bid started the auction - /// @param extended If the bid extended the auction - /// @param auction The metadata of the auction - event AuctionBid(address indexed tokenContract, uint256 indexed tokenId, bool firstBid, bool extended, Auction auction); - - /// @notice Places a bid on the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _amount The amount to bid - /// @param _finder The referrer of the bid - function createBid( - address _tokenContract, - uint256 _tokenId, - uint256 _amount, - address _finder - ) external payable nonReentrant { - // Get the auction for the specified token - Auction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - // Cache the seller - address seller = auction.seller; - - // Ensure the auction exists - require(seller != address(0), "AUCTION_DOES_NOT_EXIST"); - - // Ensure the auction has started or is valid to start - require(block.timestamp >= auction.startTime, "AUCTION_NOT_STARTED"); - - // Cache more auction metadata - uint256 firstBidTime = auction.firstBidTime; - uint256 duration = auction.duration; - address currency = auction.currency; - - // Used to emit whether the bid started the auction - bool firstBid; - - // If this is the first bid, start the auction - if (firstBidTime == 0) { - // Ensure the bid meets the reserve price - require(_amount >= auction.reservePrice, "RESERVE_PRICE_NOT_MET"); - - // Store the current time as the first bid time - auction.firstBidTime = uint96(block.timestamp); - - // Mark this bid as the first - firstBid = true; - - // Transfer the NFT from the seller into escrow for the duration of the auction - // Reverts if the seller did not approve the ERC721TransferHelper or no longer owns the token - erc721TransferHelper.transferFrom(_tokenContract, seller, address(this), _tokenId); - - // Else this is a subsequent bid, so refund the previous bidder - } else { - // Ensure the auction has not ended - require(block.timestamp < (firstBidTime + duration), "AUCTION_OVER"); - - // Cache the highest bid - uint256 highestBid = auction.highestBid; - - // Used to store the minimum bid required to outbid the highest bidder - uint256 minValidBid; - - // Calculate the minimum bid required (10% higher than the highest bid) - minValidBid = highestBid + ((highestBid * MIN_BID_INCREMENT_PERCENTAGE) / 100); - - // Ensure the incoming bid meets the minimum - require(_amount >= minValidBid, "MINIMUM_BID_NOT_MET"); - - // Refund the previous bidder - _handleOutgoingTransfer(auction.highestBidder, highestBid, currency, 50000); - } - - // Retrieve the bid from the bidder - // If ETH, this reverts if the bidder did not attach enough - // If ERC-20, this reverts if the bidder did not approve the ERC20TransferHelper or does not own the specified amount - _handleIncomingTransfer(_amount, currency); - - // Store the amount as the highest bid - auction.highestBid = _amount; - - // Store the caller as the highest bidder - auction.highestBidder = msg.sender; - - // Store the finder of the bid - auction.finder = _finder; - - // Used to emit whether the bid extended the auction - bool extended; - - // Used to store the auction time remaining - uint256 timeRemaining; - - // Get the auction time remaining - // Cannot underflow as `firstBidTime + duration` is ensured to be greater than `block.timestamp` - unchecked { - timeRemaining = firstBidTime + duration - block.timestamp; - } - - // If the bid is placed within 15 minutes of the auction end, extend the auction - if (timeRemaining < TIME_BUFFER) { - // Add (15 minutes - remaining time) to the duration so that 15 minutes remain - // Cannot underflow as `timeRemaining` is ensured to be less than `TIME_BUFFER` - unchecked { - auction.duration += uint80(TIME_BUFFER - timeRemaining); - } - - // Mark the bid as one that extended the auction - extended = true; - } - - emit AuctionBid(_tokenContract, _tokenId, firstBid, extended, auction); - } - - /// /// - /// SETTLE AUCTION /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,--------------------------. - // / \ |ReserveAuctionFindersErc20| - // Caller `------------+-------------' - // | settleAuction() | - // | --------------------------> - // | | - // | |----. - // | | | validate auction ended - // | |<---' - // | | - // | |----. - // | | | handle royalty payouts - // | |<---' - // | | - // | | - // | ___________________________________________________________ - // | ! ALT / finders fee configured for this auction? ! - // | !_____/ | ! - // | ! |----. ! - // | ! | | handle finders fee payout ! - // | ! |<---' ! - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | !~[noop]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | | - // | |----. - // | | | handle seller funds recipient payout - // | |<---' - // | | - // | |----. - // | | | transfer NFT from escrow to winning bidder - // | |<---' - // | | - // | |----. - // | | | emit AuctionEnded() - // | |<---' - // | | - // | |----. - // | | | delete auction from contract - // | |<---' - // Caller ,------------+-------------. - // ,-. |ReserveAuctionFindersErc20| - // `-' `--------------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an auction has ended - /// @param tokenContract The ERC-721 token address of the auction - /// @param tokenId The ERC-721 token id of the auction - /// @param auction The metadata of the settled auction - event AuctionEnded(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Ends the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function settleAuction(address _tokenContract, uint256 _tokenId) external nonReentrant { - // Get the auction for the specified token - Auction memory auction = auctionForNFT[_tokenContract][_tokenId]; - - // Cache the time of the first bid - uint256 firstBidTime = auction.firstBidTime; - - // Ensure the auction had started - require(firstBidTime != 0, "AUCTION_NOT_STARTED"); - - // Ensure the auction has ended - require(block.timestamp >= (firstBidTime + auction.duration), "AUCTION_NOT_OVER"); - - // Cache the auction currency - address currency = auction.currency; - - // Payout associated token royalties, if any - (uint256 remainingProfit, ) = _handleRoyaltyPayout(_tokenContract, _tokenId, auction.highestBid, currency, 300000); - - // Payout the module fee, if configured by the owner - remainingProfit = _handleProtocolFeePayout(remainingProfit, currency); - - // Cache the finder of the winning bid - address finder = auction.finder; - - // Payout the finder, if referred - if (finder != address(0)) { - // Get the fee from the remaining profit - uint256 finderFee = (remainingProfit * auction.findersFeeBps) / 10000; - - // Transfer the amount to the finder - _handleOutgoingTransfer(finder, finderFee, currency, 50000); - - // Update the remaining profit - remainingProfit -= finderFee; - } - - // Transfer the remaining profit to the funds recipient - _handleOutgoingTransfer(auction.sellerFundsRecipient, remainingProfit, currency, 50000); - - // Transfer the NFT to the winning bidder - IERC721(_tokenContract).transferFrom(address(this), auction.highestBidder, _tokenId); - - emit AuctionEnded(_tokenContract, _tokenId, auction); - - // Remove the auction from storage - delete auctionForNFT[_tokenContract][_tokenId]; - } -} diff --git a/contracts/modules/ReserveAuction/Finders/ETH/IReserveAuctionFindersEth.sol b/contracts/modules/ReserveAuction/Finders/ETH/IReserveAuctionFindersEth.sol deleted file mode 100644 index 403b66ec..00000000 --- a/contracts/modules/ReserveAuction/Finders/ETH/IReserveAuctionFindersEth.sol +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -/// @title IReserveAuctionFindersEth -/// @author kulkarohan -/// @notice Interface for Reserve Auction Finders ETH -interface IReserveAuctionFindersEth { - /// @notice Creates an auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _duration The length of time the auction should run after the first bid - /// @param _reservePrice The minimum bid amount to start the auction - /// @param _sellerFundsRecipient The address to send funds to once the auction is complete - /// @param _startTime The time that users can begin placing bids - /// @param _findersFeeBps The fee to send to the referrer of the winning bid - function createAuction( - address _tokenContract, - uint256 _tokenId, - uint256 _duration, - uint256 _reservePrice, - address _sellerFundsRecipient, - uint256 _startTime, - uint256 _findersFeeBps - ) external; - - /// @notice Updates the reserve price for a given auction - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _reservePrice The new reserve price - function setAuctionReservePrice( - address _tokenContract, - uint256 _tokenId, - uint256 _reservePrice - ) external; - - /// @notice Cancels the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function cancelAuction(address _tokenContract, uint256 _tokenId) external; - - /// @notice Places a bid on the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _finder The referrer of the bid - function createBid( - address _tokenContract, - uint256 _tokenId, - address _finder - ) external payable; - - /// @notice Ends the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function settleAuction(address _tokenContract, uint256 _tokenId) external; -} diff --git a/contracts/modules/ReserveAuction/Finders/ETH/ReserveAuctionFindersEth.sol b/contracts/modules/ReserveAuction/Finders/ETH/ReserveAuctionFindersEth.sol deleted file mode 100644 index be75146b..00000000 --- a/contracts/modules/ReserveAuction/Finders/ETH/ReserveAuctionFindersEth.sol +++ /dev/null @@ -1,555 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {ReentrancyGuard} from "@rari-capital/solmate/src/utils/ReentrancyGuard.sol"; -import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; - -import {ERC721TransferHelper} from "../../../../transferHelpers/ERC721TransferHelper.sol"; -import {FeePayoutSupportV1} from "../../../../common/FeePayoutSupport/FeePayoutSupportV1.sol"; -import {ModuleNamingSupportV1} from "../../../../common/ModuleNamingSupport/ModuleNamingSupportV1.sol"; -import {IReserveAuctionFindersEth} from "./IReserveAuctionFindersEth.sol"; - -/// @title Reserve Auction Finders ETH -/// @author kulkarohan -/// @notice Module adding Finders Fee to Reserve Auction Core ETH -contract ReserveAuctionFindersEth is IReserveAuctionFindersEth, ReentrancyGuard, FeePayoutSupportV1, ModuleNamingSupportV1 { - /// /// - /// CONSTANTS /// - /// /// - - /// @notice The minimum amount of time left in an auction after a new bid is created - uint16 constant TIME_BUFFER = 15 minutes; - - /// @notice The minimum percentage difference between two bids - uint8 constant MIN_BID_INCREMENT_PERCENTAGE = 10; - - /// /// - /// IMMUTABLES /// - /// /// - - /// @notice The ZORA ERC-721 Transfer Helper - ERC721TransferHelper public immutable erc721TransferHelper; - - /// /// - /// CONSTRUCTOR /// - /// /// - - /// @param _erc721TransferHelper The ZORA ERC-721 Transfer Helper address - /// @param _royaltyEngine The Manifold Royalty Engine address - /// @param _protocolFeeSettings The ZORA Protocol Fee Settings address - /// @param _weth The WETH token address - constructor( - address _erc721TransferHelper, - address _royaltyEngine, - address _protocolFeeSettings, - address _weth - ) - FeePayoutSupportV1(_royaltyEngine, _protocolFeeSettings, _weth, ERC721TransferHelper(_erc721TransferHelper).ZMM().registrar()) - ModuleNamingSupportV1("Reserve Auction Finders ETH") - { - erc721TransferHelper = ERC721TransferHelper(_erc721TransferHelper); - } - - /// /// - /// EIP-165 /// - /// /// - - /// @notice Implements EIP-165 for standard interface detection - /// @dev `0x01ffc9a7` is the IERC165 interface id - /// @param _interfaceId The identifier of a given interface - /// @return If the given interface is supported - function supportsInterface(bytes4 _interfaceId) external pure returns (bool) { - return _interfaceId == type(IReserveAuctionFindersEth).interfaceId || _interfaceId == 0x01ffc9a7; - } - - /// /// - /// AUCTION STORAGE /// - /// /// - - /// @notice The metadata for a given auction - /// @param seller The address of the seller - /// @param reservePrice The reserve price to start the auction - /// @param sellerFundsRecipient The address where funds are sent after the auction - /// @param highestBid The highest bid of the auction - /// @param highestBidder The address of the highest bidder - /// @param duration The length of time that the auction runs after the first bid is placed - /// @param startTime The time that the first bid can be placed - /// @param finder The address that referred the highest bid - /// @param firstBidTime The time that the first bid is placed - /// @param findersFeeBps The fee that is sent to the referrer of the highest bid - struct Auction { - address seller; - uint96 reservePrice; - address sellerFundsRecipient; - uint96 highestBid; - address highestBidder; - uint48 duration; - uint48 startTime; - address finder; - uint80 firstBidTime; - uint16 findersFeeBps; - } - - /// @notice The auction for a given NFT, if one exists - /// @dev ERC-721 token contract => ERC-721 token id => Auction - mapping(address => mapping(uint256 => Auction)) public auctionForNFT; - - /// /// - /// CREATE AUCTION /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,------------------------. - // / \ |ReserveAuctionFindersEth| - // Caller `-----------+------------' - // | createAuction() | - // | -------------------------> - // | | - // | |----. - // | | | store auction metadata - // | |<---' - // | | - // | |----. - // | | | emit AuctionCreated() - // | |<---' - // Caller ,-----------+------------. - // ,-. |ReserveAuctionFindersEth| - // `-' `------------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an auction is created - /// @param tokenContract The ERC-721 token address of the created auction - /// @param tokenId The ERC-721 token id of the created auction - /// @param auction The metadata of the created auction - event AuctionCreated(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Creates an auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _duration The length of time the auction should run after the first bid - /// @param _reservePrice The minimum bid amount to start the auction - /// @param _sellerFundsRecipient The address to send funds to once the auction is complete - /// @param _startTime The time that users can begin placing bids - /// @param _findersFeeBps The fee to send to the referrer of the winning bid - function createAuction( - address _tokenContract, - uint256 _tokenId, - uint256 _duration, - uint256 _reservePrice, - address _sellerFundsRecipient, - uint256 _startTime, - uint256 _findersFeeBps - ) external nonReentrant { - // Get the owner of the specified token - address tokenOwner = IERC721(_tokenContract).ownerOf(_tokenId); - - // Ensure the caller is the owner or an approved operator - require(msg.sender == tokenOwner || IERC721(_tokenContract).isApprovedForAll(tokenOwner, msg.sender), "ONLY_TOKEN_OWNER_OR_OPERATOR"); - - // Ensure the funds recipient is specified - require(_sellerFundsRecipient != address(0), "INVALID_FUNDS_RECIPIENT"); - - // Ensure the finders fee does not exceed 10,000 basis points - require(_findersFeeBps <= 10000, "INVALID_FINDERS_FEE"); - - // Get the auction's storage pointer - Auction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - // Store the associated metadata - auction.seller = tokenOwner; - auction.reservePrice = uint96(_reservePrice); - auction.sellerFundsRecipient = _sellerFundsRecipient; - auction.duration = uint48(_duration); - auction.startTime = uint48(_startTime); - auction.findersFeeBps = uint16(_findersFeeBps); - - emit AuctionCreated(_tokenContract, _tokenId, auction); - } - - /// /// - /// UPDATE RESERVE PRICE /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,------------------------. - // / \ |ReserveAuctionFindersEth| - // Caller `-----------+------------' - // | setAuctionReservePrice() | - // | -------------------------> - // | | - // | |----. - // | | | update reserve price - // | |<---' - // | | - // | |----. - // | | | emit AuctionReservePriceUpdated() - // | |<---' - // Caller ,-----------+------------. - // ,-. |ReserveAuctionFindersEth| - // `-' `------------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when a reserve price is updated - /// @param tokenContract The ERC-721 token address of the updated auction - /// @param tokenId The ERC-721 token id of the updated auction - /// @param auction The metadata of the updated auction - event AuctionReservePriceUpdated(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Updates the reserve price for a given auction - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _reservePrice The new reserve price - function setAuctionReservePrice( - address _tokenContract, - uint256 _tokenId, - uint256 _reservePrice - ) external nonReentrant { - // Get the auction for the specified token - Auction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - // Ensure the auction has not started - require(auction.firstBidTime == 0, "AUCTION_STARTED"); - - // Ensure the caller is the seller - require(msg.sender == auction.seller, "ONLY_SELLER"); - - // Update the reserve price - auction.reservePrice = uint96(_reservePrice); - - emit AuctionReservePriceUpdated(_tokenContract, _tokenId, auction); - } - - /// /// - /// CANCEL AUCTION /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,------------------------. - // / \ |ReserveAuctionFindersEth| - // Caller `-----------+------------' - // | cancelAuction() | - // | -------------------------> - // | | - // | |----. - // | | | emit AuctionCanceled() - // | |<---' - // | | - // | |----. - // | | | delete auction - // | |<---' - // Caller ,-----------+------------. - // ,-. |ReserveAuctionFindersEth| - // `-' `------------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an auction is canceled - /// @param tokenContract The ERC-721 token address of the canceled auction - /// @param tokenId The ERC-721 token id of the canceled auction - /// @param auction The metadata of the canceled auction - event AuctionCanceled(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Cancels the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function cancelAuction(address _tokenContract, uint256 _tokenId) external nonReentrant { - // Get the auction for the specified token - Auction memory auction = auctionForNFT[_tokenContract][_tokenId]; - - // Ensure the auction has not started - require(auction.firstBidTime == 0, "AUCTION_STARTED"); - - // Ensure the caller is the seller or a new owner of the token - require(msg.sender == auction.seller || msg.sender == IERC721(_tokenContract).ownerOf(_tokenId), "ONLY_SELLER_OR_TOKEN_OWNER"); - - emit AuctionCanceled(_tokenContract, _tokenId, auction); - - // Remove the auction from storage - delete auctionForNFT[_tokenContract][_tokenId]; - } - - /// /// - /// CREATE BID /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,------------------------. ,--------------------. - // / \ |ReserveAuctionFindersEth| |ERC721TransferHelper| - // Caller `-----------+------------' `---------+----------' - // | createBid() | | - // | -------------------------> | - // | | | - // | | | - // | ___________________________________________________________________ - // | ! ALT / First bid? | | ! - // | !_____/ | | ! - // | ! |----. | ! - // | ! | | start auction | ! - // | ! |<---' | ! - // | ! | | ! - // | ! |----. | ! - // | ! | | transferFrom() | ! - // | ! |<---' | ! - // | ! | | ! - // | ! |----. ! - // | ! | | transfer NFT from seller to escrow ! - // | ! |<---' ! - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | ! [refund previous bidder] | ! - // | ! |----. | ! - // | ! | | transfer ETH to bidder | ! - // | ! |<---' | ! - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | | | - // | | | - // | _______________________________________________ | - // | ! ALT / Bid placed within 15 min of end? ! | - // | !_____/ | ! | - // | ! |----. ! | - // | ! | | extend auction ! | - // | ! |<---' ! | - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! | - // | !~[noop]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! | - // | | | - // | |----. | - // | | | emit AuctionBid() | - // | |<---' | - // Caller ,-----------+------------. ,---------+----------. - // ,-. |ReserveAuctionFindersEth| |ERC721TransferHelper| - // `-' `------------------------' `--------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when a bid is placed - /// @param tokenContract The ERC-721 token address of the auction - /// @param tokenId The ERC-721 token id of the auction - /// @param firstBid If the bid started the auction - /// @param extended If the bid extended the auction - /// @param auction The metadata of the auction - event AuctionBid(address indexed tokenContract, uint256 indexed tokenId, bool firstBid, bool extended, Auction auction); - - /// @notice Places a bid on the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _finder The referrer of the bid - function createBid( - address _tokenContract, - uint256 _tokenId, - address _finder - ) external payable nonReentrant { - // Get the auction for the specified token - Auction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - // Cache the seller - address seller = auction.seller; - - // Ensure the auction exists - require(seller != address(0), "AUCTION_DOES_NOT_EXIST"); - - // Ensure the auction has started or is valid to start - require(block.timestamp >= auction.startTime, "AUCTION_NOT_STARTED"); - - // Cache more auction metadata - uint256 firstBidTime = auction.firstBidTime; - uint256 duration = auction.duration; - - // Used to emit whether the bid started the auction - bool firstBid; - - // If this is the first bid, start the auction - if (firstBidTime == 0) { - // Ensure the bid meets the reserve price - require(msg.value >= auction.reservePrice, "RESERVE_PRICE_NOT_MET"); - - // Store the current time as the first bid time - auction.firstBidTime = uint80(block.timestamp); - - // Mark this bid as the first - firstBid = true; - - // Transfer the NFT from the seller into escrow for the duration of the auction - // Reverts if the seller did not approve the ERC721TransferHelper or no longer owns the token - erc721TransferHelper.transferFrom(_tokenContract, seller, address(this), _tokenId); - - // Else this is a subsequent bid, so refund the previous bidder - } else { - // Ensure the auction has not ended - require(block.timestamp < (firstBidTime + duration), "AUCTION_OVER"); - - // Cache the highest bid - uint256 highestBid = auction.highestBid; - - // Used to store the minimum bid required to outbid the highest bidder - uint256 minValidBid; - - // Calculate the minimum bid required (10% higher than the highest bid) - // Cannot overflow as the highest bid would have to be magnitudes higher than the total supply of ETH - unchecked { - minValidBid = highestBid + ((highestBid * MIN_BID_INCREMENT_PERCENTAGE) / 100); - } - - // Ensure the incoming bid meets the minimum - require(msg.value >= minValidBid, "MINIMUM_BID_NOT_MET"); - - // Refund the previous bidder - _handleOutgoingTransfer(auction.highestBidder, highestBid, address(0), 50000); - } - - // Store the attached ETH as the highest bid - auction.highestBid = uint96(msg.value); - - // Store the caller as the highest bidder - auction.highestBidder = msg.sender; - - // Store the finder of the bid - auction.finder = _finder; - - // Used to emit whether the bid extended the auction - bool extended; - - // Used to store the auction time remaining - uint256 timeRemaining; - - // Get the auction time remaining - // Cannot underflow as `firstBidTime + duration` is ensured to be greater than `block.timestamp` - unchecked { - timeRemaining = firstBidTime + duration - block.timestamp; - } - - // If the bid is placed within 15 minutes of the auction end, extend the auction - if (timeRemaining < TIME_BUFFER) { - // Add (15 minutes - remaining time) to the duration so that 15 minutes remain - // Cannot underflow as `timeRemaining` is ensured to be less than `TIME_BUFFER` - unchecked { - auction.duration += uint48(TIME_BUFFER - timeRemaining); - } - - // Mark the bid as one that extended the auction - extended = true; - } - - emit AuctionBid(_tokenContract, _tokenId, firstBid, extended, auction); - } - - /// /// - /// SETTLE AUCTION /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,------------------------. - // / \ |ReserveAuctionFindersEth| - // Caller `-----------+------------' - // | settleAuction() | - // | -------------------------> - // | | - // | |----. - // | | | validate auction ended - // | |<---' - // | | - // | |----. - // | | | handle royalty payouts - // | |<---' - // | | - // | | - // | __________________________________________________________ - // | ! ALT / finders fee configured for this auction? ! - // | !_____/ | ! - // | ! |----. ! - // | ! | | handle finders fee payout ! - // | ! |<---' ! - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | !~[noop]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | | - // | |----. - // | | | handle seller funds recipient payout - // | |<---' - // | | - // | |----. - // | | | transfer NFT from escrow to winning bidder - // | |<---' - // | | - // | |----. - // | | | emit AuctionEnded() - // | |<---' - // | | - // | |----. - // | | | delete auction from contract - // | |<---' - // Caller ,-----------+------------. - // ,-. |ReserveAuctionFindersEth| - // `-' `------------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an auction has ended - /// @param tokenContract The ERC-721 token address of the auction - /// @param tokenId The ERC-721 token id of the auction - /// @param auction The metadata of the settled auction - event AuctionEnded(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Ends the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function settleAuction(address _tokenContract, uint256 _tokenId) external nonReentrant { - // Get the auction for the specified token - Auction memory auction = auctionForNFT[_tokenContract][_tokenId]; - - // Cache the time of the first bid - uint256 firstBidTime = auction.firstBidTime; - - // Ensure the auction had started - require(firstBidTime != 0, "AUCTION_NOT_STARTED"); - - // Ensure the auction has ended - require(block.timestamp >= (firstBidTime + auction.duration), "AUCTION_NOT_OVER"); - - // Payout associated token royalties, if any - (uint256 remainingProfit, ) = _handleRoyaltyPayout(_tokenContract, _tokenId, auction.highestBid, address(0), 300000); - - // Payout the module fee, if configured by the owner - remainingProfit = _handleProtocolFeePayout(remainingProfit, address(0)); - - // Cache the finder of the winning bid - address finder = auction.finder; - - // Payout the finder, if referred - if (finder != address(0)) { - // Get the fee from the remaining profit - uint256 finderFee = (remainingProfit * auction.findersFeeBps) / 10000; - - // Transfer the amount to the finder - _handleOutgoingTransfer(finder, finderFee, address(0), 50000); - - // Update the remaining profit - remainingProfit -= finderFee; - } - - // Transfer the remaining profit to the funds recipient - _handleOutgoingTransfer(auction.sellerFundsRecipient, remainingProfit, address(0), 50000); - - // Transfer the NFT to the winning bidder - IERC721(_tokenContract).transferFrom(address(this), auction.highestBidder, _tokenId); - - emit AuctionEnded(_tokenContract, _tokenId, auction); - - // Remove the auction from storage - delete auctionForNFT[_tokenContract][_tokenId]; - } -} diff --git a/contracts/modules/ReserveAuction/Listing/ETH/IReserveAuctionListingEth.sol b/contracts/modules/ReserveAuction/Listing/ETH/IReserveAuctionListingEth.sol deleted file mode 100644 index eb141a53..00000000 --- a/contracts/modules/ReserveAuction/Listing/ETH/IReserveAuctionListingEth.sol +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -/// @title IReserveAuctionListingEth -/// @author kulkarohan -/// @notice Interface for Reserve Auction Listing ETH -interface IReserveAuctionListingEth { - /// @notice Creates an auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _duration The length of time the auction should run after the first bid - /// @param _reservePrice The minimum bid amount to start the auction - /// @param _sellerFundsRecipient The address to send funds to once the auction is complete - /// @param _startTime The time that users can begin placing bids - /// @param _listingFeeBps The fee to send to the lister of the auction - /// @param _listingFeeRecipient The address listing the auction - function createAuction( - address _tokenContract, - uint256 _tokenId, - uint256 _duration, - uint256 _reservePrice, - address _sellerFundsRecipient, - uint256 _startTime, - uint256 _listingFeeBps, - address _listingFeeRecipient - ) external; - - /// @notice Updates the reserve price for a given auction - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _reservePrice The new reserve price - function setAuctionReservePrice( - address _tokenContract, - uint256 _tokenId, - uint256 _reservePrice - ) external; - - /// @notice Cancels the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function cancelAuction(address _tokenContract, uint256 _tokenId) external; - - /// @notice Places a bid on the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function createBid(address _tokenContract, uint256 _tokenId) external payable; - - /// @notice Ends the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function settleAuction(address _tokenContract, uint256 _tokenId) external; -} diff --git a/contracts/modules/ReserveAuction/Listing/ETH/ReserveAuctionListingEth.sol b/contracts/modules/ReserveAuction/Listing/ETH/ReserveAuctionListingEth.sol deleted file mode 100644 index 1cd3f40d..00000000 --- a/contracts/modules/ReserveAuction/Listing/ETH/ReserveAuctionListingEth.sol +++ /dev/null @@ -1,550 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {ReentrancyGuard} from "@rari-capital/solmate/src/utils/ReentrancyGuard.sol"; -import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; - -import {ERC721TransferHelper} from "../../../../transferHelpers/ERC721TransferHelper.sol"; -import {FeePayoutSupportV1} from "../../../../common/FeePayoutSupport/FeePayoutSupportV1.sol"; -import {ModuleNamingSupportV1} from "../../../../common/ModuleNamingSupport/ModuleNamingSupportV1.sol"; -import {IReserveAuctionListingEth} from "./IReserveAuctionListingEth.sol"; - -/// @title Reserve Auction Listing ETH -/// @author kulkarohan -/// @notice Module adding Listing Fee to Reserve Auction Core ETH -contract ReserveAuctionListingEth is IReserveAuctionListingEth, ReentrancyGuard, FeePayoutSupportV1, ModuleNamingSupportV1 { - /// /// - /// CONSTANTS /// - /// /// - - /// @notice The minimum amount of time left in an auction after a new bid is created - uint16 constant TIME_BUFFER = 15 minutes; - - /// @notice The minimum percentage difference between two bids - uint8 constant MIN_BID_INCREMENT_PERCENTAGE = 10; - - /// /// - /// IMMUTABLES /// - /// /// - - /// @notice The ZORA ERC-721 Transfer Helper - ERC721TransferHelper public immutable erc721TransferHelper; - - /// /// - /// CONSTRUCTOR /// - /// /// - - /// @param _erc721TransferHelper The ZORA ERC-721 Transfer Helper address - /// @param _royaltyEngine The Manifold Royalty Engine address - /// @param _protocolFeeSettings The ZORA Protocol Fee Settings address - /// @param _weth The WETH token address - constructor( - address _erc721TransferHelper, - address _royaltyEngine, - address _protocolFeeSettings, - address _weth - ) - FeePayoutSupportV1(_royaltyEngine, _protocolFeeSettings, _weth, ERC721TransferHelper(_erc721TransferHelper).ZMM().registrar()) - ModuleNamingSupportV1("Reserve Auction Listing ETH") - { - erc721TransferHelper = ERC721TransferHelper(_erc721TransferHelper); - } - - /// /// - /// EIP-165 /// - /// /// - - /// @notice Implements EIP-165 for standard interface detection - /// @dev `0x01ffc9a7` is the IERC165 interface id - /// @param _interfaceId The identifier of a given interface - /// @return If the given interface is supported - function supportsInterface(bytes4 _interfaceId) external pure returns (bool) { - return _interfaceId == type(IReserveAuctionListingEth).interfaceId || _interfaceId == 0x01ffc9a7; - } - - /// /// - /// AUCTION STORAGE /// - /// /// - - /// @notice The metadata for a given auction - /// @param seller The address of the seller - /// @param reservePrice The reserve price to start the auction - /// @param sellerFundsRecipient The address where funds are sent after the auction - /// @param highestBid The highest bid of the auction - /// @param highestBidder The address of the highest bidder - /// @param duration The length of time that the auction runs after the first bid is placed - /// @param startTime The time that the first bid can be placed - /// @param listingFeeRecipient The address that listed the auction - /// @param firstBidTime The time that the first bid is placed - /// @param listingFeeBps The fee that is sent to the lister of the auction - struct Auction { - address seller; - uint96 reservePrice; - address sellerFundsRecipient; - uint96 highestBid; - address highestBidder; - uint48 duration; - uint48 startTime; - address listingFeeRecipient; - uint80 firstBidTime; - uint16 listingFeeBps; - } - - /// @notice The auction for a given NFT, if one exists - /// @dev ERC-721 token contract => ERC-721 token id => Auction - mapping(address => mapping(uint256 => Auction)) public auctionForNFT; - - /// /// - /// CREATE AUCTION /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,------------------------. - // / \ |ReserveAuctionListingEth| - // Caller `-----------+------------' - // | createAuction() | - // | -------------------------> - // | | - // | |----. - // | | | store auction metadata - // | |<---' - // | | - // | |----. - // | | | emit AuctionCreated() - // | |<---' - // Caller ,-----------+------------. - // ,-. |ReserveAuctionListingEth| - // `-' `------------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an auction is created - /// @param tokenContract The ERC-721 token address of the created auction - /// @param tokenId The ERC-721 token id of the created auction - /// @param auction The metadata of the created auction - event AuctionCreated(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Creates an auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _duration The length of time the auction should run after the first bid - /// @param _reservePrice The minimum bid amount to start the auction - /// @param _sellerFundsRecipient The address to send funds to once the auction is complete - /// @param _startTime The time that users can begin placing bids - /// @param _listingFeeBps The fee to send to the lister of the auction - /// @param _listingFeeRecipient The address listing the auction - function createAuction( - address _tokenContract, - uint256 _tokenId, - uint256 _duration, - uint256 _reservePrice, - address _sellerFundsRecipient, - uint256 _startTime, - uint256 _listingFeeBps, - address _listingFeeRecipient - ) external nonReentrant { - // Get the owner of the specified token - address tokenOwner = IERC721(_tokenContract).ownerOf(_tokenId); - - // Ensure the caller is the owner or an approved operator - require(msg.sender == tokenOwner || IERC721(_tokenContract).isApprovedForAll(tokenOwner, msg.sender), "ONLY_TOKEN_OWNER_OR_OPERATOR"); - - // Ensure the funds recipient is specified - require(_sellerFundsRecipient != address(0), "INVALID_FUNDS_RECIPIENT"); - - // Ensure the listing fee does not exceed 10,000 basis points - require(_listingFeeBps <= 10000, "INVALID_LISTING_FEE"); - - // Get the auction's storage pointer - Auction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - // Store the associated metadata - auction.seller = tokenOwner; - auction.reservePrice = uint96(_reservePrice); - auction.sellerFundsRecipient = _sellerFundsRecipient; - auction.duration = uint48(_duration); - auction.startTime = uint48(_startTime); - auction.listingFeeRecipient = _listingFeeRecipient; - auction.listingFeeBps = uint16(_listingFeeBps); - - emit AuctionCreated(_tokenContract, _tokenId, auction); - } - - /// /// - /// UPDATE RESERVE PRICE /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,------------------------. - // / \ |ReserveAuctionListingEth| - // Caller `-----------+------------' - // | setAuctionReservePrice() | - // | -------------------------> - // | | - // | |----. - // | | | update reserve price - // | |<---' - // | | - // | |----. - // | | | emit AuctionReservePriceUpdated() - // | |<---' - // Caller ,-----------+------------. - // ,-. |ReserveAuctionListingEth| - // `-' `------------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when a reserve price is updated - /// @param tokenContract The ERC-721 token address of the updated auction - /// @param tokenId The ERC-721 token id of the updated auction - /// @param auction The metadata of the updated auction - event AuctionReservePriceUpdated(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Updates the reserve price for a given auction - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _reservePrice The new reserve price - function setAuctionReservePrice( - address _tokenContract, - uint256 _tokenId, - uint256 _reservePrice - ) external nonReentrant { - // Get the auction for the specified token - Auction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - // Ensure the auction has not started - require(auction.firstBidTime == 0, "AUCTION_STARTED"); - - // Ensure the caller is the seller - require(msg.sender == auction.seller, "ONLY_SELLER"); - - // Update the reserve price - auction.reservePrice = uint96(_reservePrice); - - emit AuctionReservePriceUpdated(_tokenContract, _tokenId, auction); - } - - /// /// - /// CANCEL AUCTION /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,------------------------. - // / \ |ReserveAuctionListingEth| - // Caller `-----------+------------' - // | cancelAuction() | - // | -------------------------> - // | | - // | |----. - // | | | emit AuctionCanceled() - // | |<---' - // | | - // | |----. - // | | | delete auction - // | |<---' - // Caller ,-----------+------------. - // ,-. |ReserveAuctionListingEth| - // `-' `------------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an auction is canceled - /// @param tokenContract The ERC-721 token address of the canceled auction - /// @param tokenId The ERC-721 token id of the canceled auction - /// @param auction The metadata of the canceled auction - event AuctionCanceled(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Cancels the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function cancelAuction(address _tokenContract, uint256 _tokenId) external nonReentrant { - // Get the auction for the specified token - Auction memory auction = auctionForNFT[_tokenContract][_tokenId]; - - // Ensure the auction has not started - require(auction.firstBidTime == 0, "AUCTION_STARTED"); - - // Ensure the caller is the seller or a new owner of the token - require(msg.sender == auction.seller || msg.sender == IERC721(_tokenContract).ownerOf(_tokenId), "ONLY_SELLER_OR_TOKEN_OWNER"); - - emit AuctionCanceled(_tokenContract, _tokenId, auction); - - // Remove the auction from storage - delete auctionForNFT[_tokenContract][_tokenId]; - } - - /// /// - /// CREATE BID /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,------------------------. ,--------------------. - // / \ |ReserveAuctionListingEth| |ERC721TransferHelper| - // Caller `-----------+------------' `---------+----------' - // | createBid() | | - // | -------------------------> | - // | | | - // | | | - // | ___________________________________________________________________ - // | ! ALT / First bid? | | ! - // | !_____/ | | ! - // | ! |----. | ! - // | ! | | start auction | ! - // | ! |<---' | ! - // | ! | | ! - // | ! |----. | ! - // | ! | | transferFrom() | ! - // | ! |<---' | ! - // | ! | | ! - // | ! |----. ! - // | ! | | transfer NFT from seller to escrow ! - // | ! |<---' ! - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | ! [refund previous bidder] | ! - // | ! |----. | ! - // | ! | | transfer ETH to bidder | ! - // | ! |<---' | ! - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | | | - // | | | - // | _______________________________________________ | - // | ! ALT / Bid placed within 15 min of end? ! | - // | !_____/ | ! | - // | ! |----. ! | - // | ! | | extend auction ! | - // | ! |<---' ! | - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! | - // | !~[noop]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! | - // | | | - // | |----. | - // | | | emit AuctionBid() | - // | |<---' | - // Caller ,-----------+------------. ,---------+----------. - // ,-. |ReserveAuctionListingEth| |ERC721TransferHelper| - // `-' `------------------------' `--------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when a bid is placed - /// @param tokenContract The ERC-721 token address of the auction - /// @param tokenId The ERC-721 token id of the auction - /// @param firstBid If the bid started the auction - /// @param extended If the bid extended the auction - /// @param auction The metadata of the auction - event AuctionBid(address indexed tokenContract, uint256 indexed tokenId, bool firstBid, bool extended, Auction auction); - - /// @notice Places a bid on the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function createBid(address _tokenContract, uint256 _tokenId) external payable nonReentrant { - // Get the auction for the specified token - Auction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - // Cache the seller - address seller = auction.seller; - - // Ensure the auction exists - require(seller != address(0), "AUCTION_DOES_NOT_EXIST"); - - // Ensure the auction has started or is valid to start - require(block.timestamp >= auction.startTime, "AUCTION_NOT_STARTED"); - - // Cache more auction metadata - uint256 firstBidTime = auction.firstBidTime; - uint256 duration = auction.duration; - - // Used to emit whether the bid started the auction - bool firstBid; - - // If this is the first bid, start the auction - if (firstBidTime == 0) { - // Ensure the bid meets the reserve price - require(msg.value >= auction.reservePrice, "RESERVE_PRICE_NOT_MET"); - - // Store the current time as the first bid time - auction.firstBidTime = uint80(block.timestamp); - - // Mark this bid as the first - firstBid = true; - - // Transfer the NFT from the seller into escrow for the duration of the auction - // Reverts if the seller did not approve the ERC721TransferHelper or no longer owns the token - erc721TransferHelper.transferFrom(_tokenContract, seller, address(this), _tokenId); - - // Else this is a subsequent bid, so refund the previous bidder - } else { - // Ensure the auction has not ended - require(block.timestamp < (firstBidTime + duration), "AUCTION_OVER"); - - // Cache the highest bid - uint256 highestBid = auction.highestBid; - - // Used to store the minimum bid required to outbid the highest bidder - uint256 minValidBid; - - // Calculate the minimum bid required (10% higher than the highest bid) - // Cannot overflow as the highest bid would have to be magnitudes higher than the total supply of ETH - unchecked { - minValidBid = highestBid + ((highestBid * MIN_BID_INCREMENT_PERCENTAGE) / 100); - } - - // Ensure the incoming bid meets the minimum - require(msg.value >= minValidBid, "MINIMUM_BID_NOT_MET"); - - // Refund the previous bidder - _handleOutgoingTransfer(auction.highestBidder, highestBid, address(0), 50000); - } - - // Store the attached ETH as the highest bid - auction.highestBid = uint96(msg.value); - - // Store the caller as the highest bidder - auction.highestBidder = msg.sender; - - // Used to emit whether the bid extended the auction - bool extended; - - // Used to store the auction time remaining - uint256 timeRemaining; - - // Get the auction time remaining - // Cannot underflow as `firstBidTime + duration` is ensured to be greater than `block.timestamp` - unchecked { - timeRemaining = firstBidTime + duration - block.timestamp; - } - - // If the bid is placed within 15 minutes of the auction end, extend the auction - if (timeRemaining < TIME_BUFFER) { - // Add (15 minutes - remaining time) to the duration so that 15 minutes remain - // Cannot underflow as `timeRemaining` is ensured to be less than `TIME_BUFFER` - unchecked { - auction.duration += uint48(TIME_BUFFER - timeRemaining); - } - - // Mark the bid as one that extended the auction - extended = true; - } - - emit AuctionBid(_tokenContract, _tokenId, firstBid, extended, auction); - } - - /// /// - /// SETTLE AUCTION /// - /// /// - - // ,-. - // `-' - // /|\ - // | ,------------------------. - // / \ |ReserveAuctionListingEth| - // Caller `-----------+------------' - // | settleAuction() | - // | -------------------------> - // | | - // | |----. - // | | | validate auction ended - // | |<---' - // | | - // | |----. - // | | | handle royalty payouts - // | |<---' - // | | - // | | - // | __________________________________________________________ - // | ! ALT / listing fee configured for this auction? ! - // | !_____/ | ! - // | ! |----. ! - // | ! | | handle listing fee payout ! - // | ! |<---' ! - // | !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | !~[noop]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! - // | | - // | |----. - // | | | handle seller funds recipient payout - // | |<---' - // | | - // | |----. - // | | | transfer NFT from escrow to winning bidder - // | |<---' - // | | - // | |----. - // | | | emit AuctionEnded() - // | |<---' - // | | - // | |----. - // | | | delete auction from contract - // | |<---' - // Caller ,-----------+------------. - // ,-. |ReserveAuctionListingEth| - // `-' `------------------------' - // /|\ - // | - // / \ - - /// @notice Emitted when an auction has ended - /// @param tokenContract The ERC-721 token address of the auction - /// @param tokenId The ERC-721 token id of the auction - /// @param auction The metadata of the settled auction - event AuctionEnded(address indexed tokenContract, uint256 indexed tokenId, Auction auction); - - /// @notice Ends the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function settleAuction(address _tokenContract, uint256 _tokenId) external nonReentrant { - // Get the auction for the specified token - Auction memory auction = auctionForNFT[_tokenContract][_tokenId]; - - // Cache the time of the first bid - uint256 firstBidTime = auction.firstBidTime; - - // Ensure the auction had started - require(firstBidTime != 0, "AUCTION_NOT_STARTED"); - - // Ensure the auction has ended - require(block.timestamp >= (firstBidTime + auction.duration), "AUCTION_NOT_OVER"); - - // Payout associated token royalties, if any - (uint256 remainingProfit, ) = _handleRoyaltyPayout(_tokenContract, _tokenId, auction.highestBid, address(0), 300000); - - // Payout the module fee, if configured by the owner - remainingProfit = _handleProtocolFeePayout(remainingProfit, address(0)); - - // Cache the listing fee recipient - address listingFeeRecipient = auction.listingFeeRecipient; - - // Payout the listing fee, if a recipient exists - if (listingFeeRecipient != address(0)) { - // Get the listing fee from the remaining profit - uint256 listingFee = (remainingProfit * auction.listingFeeBps) / 10000; - - // Transfer the amount to the listing fee recipient - _handleOutgoingTransfer(listingFeeRecipient, listingFee, address(0), 50000); - - // Update the remaining profit - remainingProfit -= listingFee; - } - - // Transfer the remaining profit to the funds recipient - _handleOutgoingTransfer(auction.sellerFundsRecipient, remainingProfit, address(0), 50000); - - // Transfer the NFT to the winning bidder - IERC721(_tokenContract).transferFrom(address(this), auction.highestBidder, _tokenId); - - emit AuctionEnded(_tokenContract, _tokenId, auction); - - // Remove the auction from storage - delete auctionForNFT[_tokenContract][_tokenId]; - } -} diff --git a/contracts/modules/ReserveAuction/Omnibus/IReserveAuctionOmnibus.sol b/contracts/modules/ReserveAuction/Omnibus/IReserveAuctionOmnibus.sol deleted file mode 100644 index 21f1b065..00000000 --- a/contracts/modules/ReserveAuction/Omnibus/IReserveAuctionOmnibus.sol +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {ReserveAuctionDataStorage} from "./ReserveAuctionDataStorage.sol"; - -/// @title IReserveAuctionOmnibus -/// @author kulkarohan -/// @notice Interface for Reserve Auction Core ERC-20 -interface IReserveAuctionOmnibus { - error NOT_TOKEN_OWNER_OR_OPERATOR(); - - error MODULE_NOT_APPROVED(); - - error TRANSFER_HELPER_NOT_APPROVED(); - - error DURATION_LTE_TIME_BUFFER(); - - error INVALID_EXPIRY(); - - error INVALID_LISTING_FEE(); - - error INVALID_FEES(); - - error INVALID_TOKEN_GATE(); - - error INVALID_START_TIME(); - - error INVALID_TIME_BUFFER(); - - error INVALID_PERCENT_INCREMENT(); - - error RESERVE_PRICE_NOT_MET(); - - error AUCTION_STARTED(); - - error AUCTION_OVER(); - - error AUCTION_NOT_STARTED(); - - error AUCTION_NOT_OVER(); - - error AUCTION_DOES_NOT_EXIST(); - - error AUCTION_EXPIRED(); - - error TOKEN_GATE_INSUFFICIENT_BALANCE(); - - error MINIMUM_BID_NOT_MET(); - - struct CreateAuctionParameters { - uint256 tokenId; - uint256 reservePrice; - uint256 startTime; - uint256 tokenGateMinAmount; - address tokenContract; - uint64 duration; - uint16 findersFeeBps; - uint16 timeBuffer; - address fundsRecipient; - uint96 expiry; - address listingFeeRecipient; - uint16 listingFeeBps; - uint8 percentIncrement; - address tokenGateToken; - address bidCurrency; - } - - function createAuctionMinimal( - address _tokenContract, - uint256 _tokenId, - uint256 _reservePrice, - uint64 _duration - ) external; - - function createAuction(CreateAuctionParameters calldata auctionData) external; - - function setAuctionReservePrice( - address _tokenContract, - uint256 _tokenId, - uint256 _reservePrice - ) external; - - function cancelAuction(address _tokenContract, uint256 _tokenId) external; - - function createBid( - address _tokenContract, - uint256 _tokenId, - uint256 _amount, - address finder - ) external payable; - - function settleAuction(address _tokenContract, uint256 _tokenId) external; -} diff --git a/contracts/modules/ReserveAuction/Omnibus/ReserveAuctionDataStorage.sol b/contracts/modules/ReserveAuction/Omnibus/ReserveAuctionDataStorage.sol deleted file mode 100644 index 75f3c0e4..00000000 --- a/contracts/modules/ReserveAuction/Omnibus/ReserveAuctionDataStorage.sol +++ /dev/null @@ -1,201 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -uint32 constant FEATURE_MASK_LISTING_FEE = 1 << 3; -uint32 constant FEATURE_MASK_FINDERS_FEE = 1 << 4; -uint32 constant FEATURE_MASK_ERC20_CURRENCY = 1 << 5; -uint32 constant FEATURE_MASK_TOKEN_GATE = 1 << 6; -uint32 constant FEATURE_MASK_START_TIME = 1 << 7; -uint32 constant FEATURE_MASK_RECIPIENT_OR_EXPIRY = 1 << 8; -uint32 constant FEATURE_MASK_BUFFER_AND_INCREMENT = 1 << 9; - -contract ReserveAuctionDataStorage { - struct StoredAuction { - uint256 reservePrice; - address seller; - uint64 duration; - uint32 features; - mapping(uint32 => uint256) featureData; - } - - struct OngoingAuction { - uint96 firstBidTime; - address highestBidder; - uint256 highestBid; - } - - /// @notice The auction for a given NFT, if one exists - /// @dev ERC-721 token contract => ERC-721 token id => Auction - mapping(address => mapping(uint256 => StoredAuction)) public auctionForNFT; - mapping(address => mapping(uint256 => OngoingAuction)) public ongoingAuctionForNFT; - - function _getListingFee(StoredAuction storage auction) internal view returns (uint16 listingFeeBps, address listingFeeRecipient) { - uint256 data = auction.featureData[FEATURE_MASK_LISTING_FEE]; - listingFeeBps = uint16(data); - listingFeeRecipient = address(uint160(data >> 16)); - } - - function _setListingFee( - StoredAuction storage auction, - uint16 listingFeeBps, - address listingFeeRecipient - ) internal { - auction.features |= FEATURE_MASK_LISTING_FEE; - auction.featureData[FEATURE_MASK_LISTING_FEE] = listingFeeBps | (uint256(uint160(listingFeeRecipient)) << 16); - } - - function _getTokenGate(StoredAuction storage auction) internal view returns (address token, uint256 minAmount) { - token = address(uint160(auction.featureData[FEATURE_MASK_TOKEN_GATE])); - minAmount = auction.featureData[FEATURE_MASK_TOKEN_GATE + 1]; - } - - function _setTokenGate( - StoredAuction storage auction, - address token, - uint256 minAmount - ) internal { - auction.features |= FEATURE_MASK_TOKEN_GATE; - auction.featureData[FEATURE_MASK_TOKEN_GATE] = uint256(uint160(token)); - auction.featureData[FEATURE_MASK_TOKEN_GATE + 1] = minAmount; - } - - function _getFindersFee(StoredAuction storage auction) internal view returns (uint16 findersFeeBps, address finder) { - uint256 data = auction.featureData[FEATURE_MASK_FINDERS_FEE]; - - findersFeeBps = uint16(data); - finder = address(uint160(data >> 16)); - } - - function _setFindersFee( - StoredAuction storage auction, - uint16 findersFeeBps, - address finder - ) internal { - auction.features |= FEATURE_MASK_FINDERS_FEE; - auction.featureData[FEATURE_MASK_FINDERS_FEE] = findersFeeBps | (uint256(uint160(finder)) << 16); - } - - function _getStartTime(StoredAuction storage auction) internal view returns (uint256) { - return auction.featureData[FEATURE_MASK_START_TIME]; - } - - function _setStartTime(StoredAuction storage auction, uint256 startTime) internal { - auction.features |= FEATURE_MASK_START_TIME; - auction.featureData[FEATURE_MASK_START_TIME] = startTime; - } - - function _getERC20CurrencyWithFallback(StoredAuction storage auction) internal view returns (address) { - if (!_hasFeature(auction.features, FEATURE_MASK_ERC20_CURRENCY)) { - return address(0); - } - return address(uint160(auction.featureData[FEATURE_MASK_ERC20_CURRENCY])); - } - - function _setERC20Currency(StoredAuction storage auction, address currency) internal { - auction.features |= FEATURE_MASK_ERC20_CURRENCY; - auction.featureData[FEATURE_MASK_ERC20_CURRENCY] = uint256(uint160(currency)); - } - - function _getExpiryAndFundsRecipient(StoredAuction storage auction) internal view returns (uint96 expiry, address fundsRecipient) { - uint256 data = auction.featureData[FEATURE_MASK_RECIPIENT_OR_EXPIRY]; - expiry = uint96(data); - fundsRecipient = address(uint160(data >> 96)); - } - - function _setExpiryAndFundsRecipient( - StoredAuction storage auction, - uint96 expiry, - address fundsRecipient - ) internal { - auction.features |= FEATURE_MASK_RECIPIENT_OR_EXPIRY; - auction.featureData[FEATURE_MASK_RECIPIENT_OR_EXPIRY] = expiry | (uint256(uint160(fundsRecipient)) << 96); - } - - function _getBufferAndIncrement(StoredAuction storage auction) internal view returns (uint16 timeBuffer, uint8 percentIncrement) { - uint256 data = auction.featureData[FEATURE_MASK_BUFFER_AND_INCREMENT]; - timeBuffer = uint16(data); - percentIncrement = uint8(data >> 16); - } - - function _setBufferAndIncrement( - StoredAuction storage auction, - uint16 timeBuffer, - uint8 percentIncrement - ) internal { - auction.features |= FEATURE_MASK_BUFFER_AND_INCREMENT; - auction.featureData[FEATURE_MASK_BUFFER_AND_INCREMENT] = uint256(timeBuffer) | (uint256(percentIncrement) << 16); - } - - struct FullAuction { - uint256 reservePrice; - uint256 startTime; - uint256 tokenGateMinAmount; - address seller; - uint96 expiry; - address currency; - uint64 duration; - uint32 features; - address finder; - uint16 findersFeeBps; - uint16 timeBuffer; - uint8 percentIncrement; - address fundsRecipient; - address listingFeeRecipient; - address tokenGateToken; - uint16 listingFeeBps; - OngoingAuction ongoingAuction; - } - - function _hasFeature(uint32 features, uint32 feature) internal pure returns (bool) { - return (features & feature) == feature; - } - - function _getFullAuction(address tokenContract, uint256 tokenId) internal view returns (FullAuction memory) { - StoredAuction storage auction = auctionForNFT[tokenContract][tokenId]; - - uint32 features = auction.features; - FullAuction memory fullAuction; - - fullAuction.currency = _getERC20CurrencyWithFallback(auction); - - if (_hasFeature(features, FEATURE_MASK_TOKEN_GATE)) { - (fullAuction.tokenGateToken, fullAuction.tokenGateMinAmount) = _getTokenGate(auction); - } - - if (_hasFeature(features, FEATURE_MASK_LISTING_FEE)) { - (fullAuction.listingFeeBps, fullAuction.listingFeeRecipient) = _getListingFee(auction); - } - - if (_hasFeature(features, FEATURE_MASK_START_TIME)) { - fullAuction.startTime = _getStartTime(auction); - } - - if (_hasFeature(features, FEATURE_MASK_FINDERS_FEE)) { - (fullAuction.findersFeeBps, fullAuction.finder) = _getFindersFee(auction); - } - - if (_hasFeature(features, FEATURE_MASK_ERC20_CURRENCY)) { - fullAuction.currency = _getERC20CurrencyWithFallback(auction); - } - - if (_hasFeature(features, FEATURE_MASK_RECIPIENT_OR_EXPIRY)) { - (uint96 _expiry, address _fundsRecipient) = _getExpiryAndFundsRecipient(auction); - fullAuction.expiry = _expiry; - fullAuction.fundsRecipient = _fundsRecipient; - } - - if (_hasFeature(features, FEATURE_MASK_BUFFER_AND_INCREMENT)) { - (fullAuction.timeBuffer, fullAuction.percentIncrement) = _getBufferAndIncrement(auction); - } - - OngoingAuction memory _ongoingAuction = ongoingAuctionForNFT[tokenContract][tokenId]; - - fullAuction.seller = auction.seller; - fullAuction.reservePrice = auction.reservePrice; - fullAuction.duration = auction.duration; - fullAuction.features = auction.features; - fullAuction.ongoingAuction = _ongoingAuction; - - return fullAuction; - } -} diff --git a/contracts/modules/ReserveAuction/Omnibus/ReserveAuctionOmnibus.sol b/contracts/modules/ReserveAuction/Omnibus/ReserveAuctionOmnibus.sol deleted file mode 100644 index 6fea1712..00000000 --- a/contracts/modules/ReserveAuction/Omnibus/ReserveAuctionOmnibus.sol +++ /dev/null @@ -1,504 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {ReentrancyGuard} from "@rari-capital/solmate/src/utils/ReentrancyGuard.sol"; -import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import {ERC721TransferHelper} from "../../../transferHelpers/ERC721TransferHelper.sol"; -import {IncomingTransferSupportV1} from "../../../common/IncomingTransferSupport/V1/IncomingTransferSupportV1.sol"; -import {FeePayoutSupportV1} from "../../../common/FeePayoutSupport/FeePayoutSupportV1.sol"; -import {ModuleNamingSupportV1} from "../../../common/ModuleNamingSupport/ModuleNamingSupportV1.sol"; - -import {IReserveAuctionOmnibus} from "./IReserveAuctionOmnibus.sol"; -import {ReserveAuctionDataStorage, FEATURE_MASK_LISTING_FEE, FEATURE_MASK_FINDERS_FEE, FEATURE_MASK_ERC20_CURRENCY, FEATURE_MASK_TOKEN_GATE, FEATURE_MASK_START_TIME, FEATURE_MASK_RECIPIENT_OR_EXPIRY, FEATURE_MASK_BUFFER_AND_INCREMENT} from "./ReserveAuctionDataStorage.sol"; - -/// @title Reserve Auction Omnibus -/// @author jgeary -/// @notice Omnibus module for multi-featured reserve auctions for ERC-721 tokens -contract ReserveAuctionOmnibus is - IReserveAuctionOmnibus, - ReentrancyGuard, - IncomingTransferSupportV1, - FeePayoutSupportV1, - ModuleNamingSupportV1, - ReserveAuctionDataStorage -{ - /// @notice The minimum amount of time left in an auction after a new bid is created - uint16 constant DEFAULT_TIME_BUFFER = 15 minutes; - uint16 constant MINIMUM_TIME_BUFFER = 1 minutes; - uint16 constant MAXIMUM_TIME_BUFFER = 1 hours; - - /// @notice The minimum percentage difference between two bids - uint8 constant DEFAULT_MIN_BID_INCREMENT_PERCENTAGE = 10; - uint8 constant MAXIMUM_MIN_BID_INCREMENT_PERCENTAGE = 50; - - /// @notice The ZORA ERC-721 Transfer Helper - ERC721TransferHelper public immutable erc721TransferHelper; - - /// @notice Emitted when an auction is created - /// @param tokenContract The ERC-721 token address of the created auction - /// @param tokenId The ERC-721 token id of the created auction - /// @param auction The metadata of the created auction - event AuctionCreated(address indexed tokenContract, uint256 indexed tokenId, FullAuction auction); - - /// @notice Emitted when a reserve price is updated - /// @param tokenContract The ERC-721 token address of the updated auction - /// @param tokenId The ERC-721 token id of the updated auction - /// @param auction The metadata of the updated auction - event AuctionReservePriceUpdated(address indexed tokenContract, uint256 indexed tokenId, FullAuction auction); - - /// @notice Emitted when an auction is canceled - /// @param tokenContract The ERC-721 token address of the canceled auction - /// @param tokenId The ERC-721 token id of the canceled auction - /// @param auction The metadata of the canceled auction - event AuctionCanceled(address indexed tokenContract, uint256 indexed tokenId, FullAuction auction); - - /// @notice Emitted when a bid is placed - /// @param tokenContract The ERC-721 token address of the auction - /// @param tokenId The ERC-721 token id of the auction - /// @param firstBid If the bid started the auction - /// @param extended If the bid extended the auction - /// @param auction The metadata of the auction - event AuctionBid(address indexed tokenContract, uint256 indexed tokenId, bool firstBid, bool extended, FullAuction auction); - - /// @notice Emitted when an auction has ended - /// @param tokenContract The ERC-721 token address of the auction - /// @param tokenId The ERC-721 token id of the auction - /// @param auction The metadata of the settled auction - event AuctionEnded(address indexed tokenContract, uint256 indexed tokenId, FullAuction auction); - - /// @param _erc20TransferHelper The ZORA ERC-20 Transfer Helper address - /// @param _erc721TransferHelper The ZORA ERC-721 Transfer Helper address - /// @param _royaltyEngine The Manifold Royalty Engine address - /// @param _protocolFeeSettings The ZORA Protocol Fee Settings address - /// @param _weth The WETH token address - constructor( - address _erc20TransferHelper, - address _erc721TransferHelper, - address _royaltyEngine, - address _protocolFeeSettings, - address _weth - ) - IncomingTransferSupportV1(_erc20TransferHelper) - FeePayoutSupportV1(_royaltyEngine, _protocolFeeSettings, _weth, ERC721TransferHelper(_erc721TransferHelper).ZMM().registrar()) - ModuleNamingSupportV1("Reserve Auction Omnibus: ERC20 / Listing Fee / Token Gate / Start Time / Expiry") - { - erc721TransferHelper = ERC721TransferHelper(_erc721TransferHelper); - } - - /// @notice Implements EIP-165 for standard interface detection - /// @dev `0x01ffc9a7` is the IERC165 interface id - /// @param _interfaceId The identifier of a given interface - /// @return If the given interface is supported - function supportsInterface(bytes4 _interfaceId) external pure returns (bool) { - return _interfaceId == type(IReserveAuctionOmnibus).interfaceId || _interfaceId == 0x01ffc9a7; - } - - /// @notice Creates a simple ETH auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _reservePrice The ETH price to start bidding - /// @param _duration The duration of the auction in seconds - function createAuctionMinimal( - address _tokenContract, - uint256 _tokenId, - uint256 _reservePrice, - uint64 _duration - ) external nonReentrant { - // Get the owner of the specified token - address tokenOwner = IERC721(_tokenContract).ownerOf(_tokenId); - - // Ensure the caller is the owner or an approved operator - if (msg.sender != tokenOwner && !IERC721(_tokenContract).isApprovedForAll(tokenOwner, msg.sender)) revert NOT_TOKEN_OWNER_OR_OPERATOR(); - if (!erc721TransferHelper.isModuleApproved(msg.sender)) revert MODULE_NOT_APPROVED(); - if (!IERC721(_tokenContract).isApprovedForAll(tokenOwner, address(erc721TransferHelper))) revert TRANSFER_HELPER_NOT_APPROVED(); - - if (_duration <= DEFAULT_TIME_BUFFER) revert DURATION_LTE_TIME_BUFFER(); - - StoredAuction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - // Clear features (if re-used from another auction on the same token) - auction.features = 0; - - // Store the auction metadata - auction.seller = tokenOwner; - auction.reservePrice = _reservePrice; - auction.duration = _duration; - - emit AuctionCreated(_tokenContract, _tokenId, _getFullAuction(_tokenContract, _tokenId)); - } - - /// @notice Creates an auction for a given NFT - /// @param auctionData The CreateAuctionParameters struct containing the auction parameters - function createAuction(IReserveAuctionOmnibus.CreateAuctionParameters calldata auctionData) external nonReentrant { - // Get the owner of the specified token - address tokenOwner = IERC721(auctionData.tokenContract).ownerOf(auctionData.tokenId); - - // Ensure the caller is the owner or an approved operator - if (msg.sender != tokenOwner && !IERC721(auctionData.tokenContract).isApprovedForAll(tokenOwner, msg.sender)) - revert NOT_TOKEN_OWNER_OR_OPERATOR(); - if (!erc721TransferHelper.isModuleApproved(msg.sender)) revert MODULE_NOT_APPROVED(); - if (!IERC721(auctionData.tokenContract).isApprovedForAll(tokenOwner, address(erc721TransferHelper))) revert TRANSFER_HELPER_NOT_APPROVED(); - - if (auctionData.timeBuffer > 0) { - if (auctionData.duration <= auctionData.timeBuffer) revert DURATION_LTE_TIME_BUFFER(); - } else { - if (auctionData.duration <= DEFAULT_TIME_BUFFER) revert DURATION_LTE_TIME_BUFFER(); - } - - StoredAuction storage auction = auctionForNFT[auctionData.tokenContract][auctionData.tokenId]; - - // Clear features (if re-used from another auction on the same token) - auction.features = 0; - - if (auctionData.expiry > 0 || (auctionData.fundsRecipient != address(0) && auctionData.fundsRecipient != tokenOwner)) { - if (auctionData.expiry != 0 && auctionData.expiry <= block.timestamp) revert INVALID_EXPIRY(); - _setExpiryAndFundsRecipient(auction, auctionData.expiry, auctionData.fundsRecipient); - } - - if ( - (auctionData.listingFeeBps > 0 && auctionData.listingFeeRecipient == address(0)) || - (auctionData.listingFeeBps == 0 && auctionData.listingFeeRecipient != address(0)) - ) revert INVALID_LISTING_FEE(); - if (auctionData.listingFeeBps + auctionData.findersFeeBps > 10000) revert INVALID_FEES(); - - if (auctionData.listingFeeBps > 0 && auctionData.listingFeeRecipient != address(0)) { - _setListingFee(auction, auctionData.listingFeeBps, auctionData.listingFeeRecipient); - } - - if (auctionData.findersFeeBps > 0) { - _setFindersFee(auction, auctionData.findersFeeBps, address(0)); - } - - if ( - (auctionData.tokenGateMinAmount > 0 && auctionData.tokenGateToken == address(0)) || - (auctionData.tokenGateMinAmount == 0 && auctionData.tokenGateToken != address(0)) - ) revert INVALID_TOKEN_GATE(); - - if (auctionData.tokenGateToken != address(0)) { - _setTokenGate(auction, auctionData.tokenGateToken, auctionData.tokenGateMinAmount); - } - - if (auctionData.startTime > 0) { - if (auctionData.startTime <= block.timestamp || (auctionData.expiry > 0 && auctionData.expiry <= auctionData.startTime)) - revert INVALID_START_TIME(); - _setStartTime(auction, auctionData.startTime); - } - - if (auctionData.bidCurrency != address(0)) { - _setERC20Currency(auction, auctionData.bidCurrency); - } - - if (auctionData.timeBuffer > 0 || auctionData.percentIncrement > 0) { - if (auctionData.timeBuffer > 0 && (auctionData.timeBuffer < MINIMUM_TIME_BUFFER || auctionData.timeBuffer > MAXIMUM_TIME_BUFFER)) - revert INVALID_TIME_BUFFER(); - if (auctionData.percentIncrement > 0 && auctionData.percentIncrement > MAXIMUM_MIN_BID_INCREMENT_PERCENTAGE) - revert INVALID_PERCENT_INCREMENT(); - _setBufferAndIncrement(auction, auctionData.timeBuffer, auctionData.percentIncrement); - } - - // Store the auction metadata - auction.seller = tokenOwner; - auction.reservePrice = auctionData.reservePrice; - auction.duration = auctionData.duration; - - FullAuction memory fullAuction = _getFullAuction(auctionData.tokenContract, auctionData.tokenId); - emit AuctionCreated(auctionData.tokenContract, auctionData.tokenId, fullAuction); - } - - /// @notice Updates the reserve price for a given auction - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _reservePrice The new reserve price - function setAuctionReservePrice( - address _tokenContract, - uint256 _tokenId, - uint256 _reservePrice - ) external nonReentrant { - // Get the auction for the specified token - StoredAuction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - if (auction.seller == address(0)) { - revert AUCTION_DOES_NOT_EXIST(); - } - - if (ongoingAuctionForNFT[_tokenContract][_tokenId].firstBidTime > 0) { - revert AUCTION_STARTED(); - } - - // Ensure the caller is the seller - if (msg.sender != auction.seller && !IERC721(_tokenContract).isApprovedForAll(auction.seller, msg.sender)) { - revert NOT_TOKEN_OWNER_OR_OPERATOR(); - } - - // Update the reserve price - auction.reservePrice = _reservePrice; - - emit AuctionReservePriceUpdated(_tokenContract, _tokenId, _getFullAuction(_tokenContract, _tokenId)); - } - - /// @notice Cancels the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function cancelAuction(address _tokenContract, uint256 _tokenId) external nonReentrant { - // Get the auction for the specified token - StoredAuction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - // Ensure the auction has not started - if (ongoingAuctionForNFT[_tokenContract][_tokenId].firstBidTime > 0) { - revert AUCTION_STARTED(); - } - - // If token is still owned by seller, only seller or operator can cancel (otherwise public) - if ( - IERC721(_tokenContract).ownerOf(_tokenId) == auction.seller && - msg.sender != auction.seller && - !IERC721(_tokenContract).isApprovedForAll(auction.seller, msg.sender) - ) { - revert NOT_TOKEN_OWNER_OR_OPERATOR(); - } - - emit AuctionCanceled(_tokenContract, _tokenId, _getFullAuction(_tokenContract, _tokenId)); - - // Remove the auction from storage - delete auctionForNFT[_tokenContract][_tokenId]; - } - - /// @notice Places a bid on the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - /// @param _amount The amount to bid - function createBid( - address _tokenContract, - uint256 _tokenId, - uint256 _amount, - address _finder - ) external payable nonReentrant { - // Get the auction for the specified token - StoredAuction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - // Cache the seller - address seller = auction.seller; - - // Ensure the auction exists - if (seller == address(0)) revert AUCTION_DOES_NOT_EXIST(); - - // Cache features - uint32 features = auction.features; - - if (_hasFeature(features, FEATURE_MASK_START_TIME)) { - uint256 startTime = _getStartTime(auction); - if (block.timestamp < startTime) revert AUCTION_NOT_STARTED(); - } - - if (_hasFeature(auction.features, FEATURE_MASK_TOKEN_GATE)) { - (address tokenGateToken, uint256 tokenGateMinAmount) = _getTokenGate(auction); - if (IERC20(tokenGateToken).balanceOf(msg.sender) < tokenGateMinAmount) revert TOKEN_GATE_INSUFFICIENT_BALANCE(); - } - - // Used to emit whether the bid started the auction - bool firstBid; - - OngoingAuction memory ongoingAuction = ongoingAuctionForNFT[_tokenContract][_tokenId]; - - address currency = _getERC20CurrencyWithFallback(auction); - - // If this is the first bid, start the auction - if (ongoingAuction.firstBidTime == 0) { - // Ensure the bid meets the reserve price - if (_amount < auction.reservePrice) revert RESERVE_PRICE_NOT_MET(); - - if (_hasFeature(auction.features, FEATURE_MASK_RECIPIENT_OR_EXPIRY)) { - (uint96 expiry, ) = _getExpiryAndFundsRecipient(auction); - if (expiry > 0 && expiry < block.timestamp) revert AUCTION_EXPIRED(); - } - - // Store the amount as the highest bid - ongoingAuction = OngoingAuction({highestBid: _amount, highestBidder: msg.sender, firstBidTime: uint96(block.timestamp)}); - - // Mark this bid as the first - firstBid = true; - - // Transfer the NFT from the seller into escrow for the duration of the auction - // Reverts if the seller did not approve the ERC721TransferHelper or no longer owns the token - erc721TransferHelper.transferFrom(_tokenContract, seller, address(this), _tokenId); - - // Else this is a subsequent bid, so refund the previous bidder - } else { - // Ensure the auction has not ended - if (block.timestamp >= (ongoingAuction.firstBidTime + auction.duration)) revert AUCTION_OVER(); - - // Cache the highest bid - uint256 highestBid = ongoingAuction.highestBid; - - // Used to store the minimum bid required to outbid the highest bidder - uint256 minValidBid; - - uint8 percentIncrement; - if (_hasFeature(features, FEATURE_MASK_BUFFER_AND_INCREMENT)) { - (, percentIncrement) = _getBufferAndIncrement(auction); - } - if (percentIncrement == 0) percentIncrement = DEFAULT_MIN_BID_INCREMENT_PERCENTAGE; - - // Calculate the minimum bid required - // TODO: audit overflow potential now that prices are uint256 - unchecked { - minValidBid = highestBid + ((highestBid * percentIncrement) / 100); - } - - // Ensure the incoming bid meets the minimum - if (_amount < minValidBid) revert MINIMUM_BID_NOT_MET(); - - // Refund the previous bidder - _handleOutgoingTransfer(ongoingAuction.highestBidder, highestBid, currency, 50000); - - ongoingAuction.highestBid = _amount; - ongoingAuction.highestBidder = msg.sender; - } - - if (_hasFeature(auction.features, FEATURE_MASK_FINDERS_FEE)) { - (uint16 findersFeeBps, ) = _getFindersFee(auction); - _setFindersFee(auction, findersFeeBps, _finder); - } - - // Retrieve the bid from the bidder - // If ETH, this reverts if the bidder did not attach enough - // If ERC-20, this reverts if the bidder did not approve the ERC20TransferHelper or does not own the specified amount - _handleIncomingTransfer(_amount, currency); - - // Used to emit whether the bid extended the auction - bool extended; - - // Used to store the auction time remaining - uint256 timeRemaining; - - // Get the auction time remaining - // Cannot underflow as `firstBidTime + duration` is ensured to be greater than `block.timestamp` - unchecked { - timeRemaining = ongoingAuction.firstBidTime + auction.duration - block.timestamp; - } - - uint16 timeBuffer; - if (_hasFeature(features, FEATURE_MASK_BUFFER_AND_INCREMENT)) { - (timeBuffer, ) = _getBufferAndIncrement(auction); - } - if (timeBuffer == 0) timeBuffer = DEFAULT_TIME_BUFFER; - - // If the bid is placed within 15 minutes of the auction end, extend the auction - if (timeRemaining < timeBuffer) { - // Add (15 minutes - remaining time) to the duration so that 15 minutes remain - // Cannot underflow as `timeRemaining` is ensured to be less than `TIME_BUFFER` - unchecked { - auction.duration += uint64(timeBuffer - timeRemaining); - } - - // Mark the bid as one that extended the auction - extended = true; - } - - ongoingAuctionForNFT[_tokenContract][_tokenId] = ongoingAuction; - FullAuction memory fullAuction = _getFullAuction(_tokenContract, _tokenId); - emit AuctionBid(_tokenContract, _tokenId, firstBid, extended, fullAuction); - } - - function _handleListingAndFindersFees( - uint256 _remainingProfit, - StoredAuction storage auction, - address currency - ) internal returns (uint256 remainingProfit) { - remainingProfit = _remainingProfit; - uint256 listingFee; - address listingFeeRecipient; - uint256 findersFee; - address finder; - - if (_hasFeature(auction.features, FEATURE_MASK_LISTING_FEE)) { - uint16 listingFeeBps; - (listingFeeBps, listingFeeRecipient) = _getListingFee(auction); - listingFee = (remainingProfit * listingFeeBps) / 10000; - } - - if (_hasFeature(auction.features, FEATURE_MASK_FINDERS_FEE)) { - uint16 findersFeeBps; - (findersFeeBps, finder) = _getFindersFee(auction); - if (finder != address(0)) { - findersFee = (remainingProfit * findersFeeBps) / 10000; - } - } - - if (listingFee > 0) { - _handleOutgoingTransfer(listingFeeRecipient, listingFee, currency, 50000); - remainingProfit -= listingFee; - } - - if (findersFee > 0) { - _handleOutgoingTransfer(finder, findersFee, currency, 50000); - remainingProfit -= findersFee; - } - } - - function _handleSellerPayout( - uint256 profit, - StoredAuction storage auction, - address currency - ) internal { - address fundsRecipient = auction.seller; - - if (_hasFeature(auction.features, FEATURE_MASK_RECIPIENT_OR_EXPIRY)) { - (, address _fundsRecipient) = _getExpiryAndFundsRecipient(auction); - if (_fundsRecipient != address(0)) { - fundsRecipient = _fundsRecipient; - } - } - - // Transfer the remaining profit to the funds recipient - _handleOutgoingTransfer(fundsRecipient, profit, currency, 50000); - } - - /// @notice Ends the auction for a given NFT - /// @param _tokenContract The address of the ERC-721 token - /// @param _tokenId The id of the ERC-721 token - function settleAuction(address _tokenContract, uint256 _tokenId) external nonReentrant { - // Get the auction for the specified token - StoredAuction storage auction = auctionForNFT[_tokenContract][_tokenId]; - - OngoingAuction memory ongoingAuction = ongoingAuctionForNFT[_tokenContract][_tokenId]; - - // Cache the time of the first bid - uint256 firstBidTime = ongoingAuction.firstBidTime; - - // Ensure the auction had started - if (firstBidTime == 0) revert AUCTION_NOT_STARTED(); - - // Ensure the auction has ended - if (block.timestamp < (firstBidTime + auction.duration)) revert AUCTION_NOT_OVER(); - - // Cache the auction currency - address currency = _getERC20CurrencyWithFallback(auction); - - // Payout associated token royalties, if any - (uint256 remainingProfit, ) = _handleRoyaltyPayout(_tokenContract, _tokenId, ongoingAuction.highestBid, currency, 300000); - - // Payout the module fee, if configured by the owner - remainingProfit = _handleProtocolFeePayout(remainingProfit, currency); - - remainingProfit = _handleListingAndFindersFees(remainingProfit, auction, currency); - - _handleSellerPayout(remainingProfit, auction, currency); - - // Transfer the NFT to the winning bidder - IERC721(_tokenContract).transferFrom(address(this), ongoingAuction.highestBidder, _tokenId); - - emit AuctionEnded(_tokenContract, _tokenId, _getFullAuction(_tokenContract, _tokenId)); - - // Remove the auction from storage - delete auctionForNFT[_tokenContract][_tokenId]; - // Remove the auction ongoing state from storage - delete ongoingAuctionForNFT[_tokenContract][_tokenId]; - } - - function getFullAuction(address _tokenContract, uint256 _tokenId) external view returns (FullAuction memory) { - return _getFullAuction(_tokenContract, _tokenId); - } -} diff --git a/contracts/test/modules/Asks/Core/ERC20/AsksCoreErc20.integration.t.sol b/contracts/test/modules/Asks/Core/ERC20/AsksCoreErc20.integration.t.sol deleted file mode 100644 index fa4323ec..00000000 --- a/contracts/test/modules/Asks/Core/ERC20/AsksCoreErc20.integration.t.sol +++ /dev/null @@ -1,136 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {AsksCoreErc20} from "../../../../../modules/Asks/Core/ERC20/AsksCoreErc20.sol"; -import {Zorb} from "../../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../../utils/modules/RoyaltyEngine.sol"; - -import {TestERC721} from "../../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../../utils/tokens/WETH.sol"; -import {VM} from "../../../../utils/VM.sol"; - -/// @title AsksCoreErc20IntegrationTest -/// @notice Integration Tests for Asks Core ERC-20 -contract AsksCoreErc20IntegrationTest is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - AsksCoreErc20 internal asks; - TestERC721 internal token; - WETH internal weth; - - Zorb internal seller; - Zorb internal operator; - Zorb internal buyer; - Zorb internal finder; - Zorb internal sellerFundsRecipient; - Zorb internal royaltyRecipient; - Zorb internal protocolFeeRecipient; - - function setUp() public { - // Cheatcodes - vm = VM(HEVM_ADDRESS); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - seller = new Zorb(address(ZMM)); - operator = new Zorb(address(ZMM)); - buyer = new Zorb(address(ZMM)); - finder = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - protocolFeeRecipient = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - token = new TestERC721(); - weth = new WETH(); - - // Deploy Asks Core ERC-20 - asks = new AsksCoreErc20(address(erc20TransferHelper), address(erc721TransferHelper), address(royaltyEngine), address(ZPFS), address(weth)); - registrar.registerModule(address(asks)); - - // Set module fee - vm.prank(address(registrar)); - ZPFS.setFeeParams(address(asks), address(protocolFeeRecipient), 1); - - // Set buyer balance - vm.deal(address(buyer), 100 ether); - - // Mint seller token - token.mint(address(seller), 0); - - // Buyer swap 50 ETH <> 50 WETH - vm.prank(address(buyer)); - weth.deposit{value: 50 ether}(); - - // Users approve Asks module - seller.setApprovalForModule(address(asks), true); - buyer.setApprovalForModule(address(asks), true); - - // Seller approve ERC721TransferHelper - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - - // Buyer approve ERC20TransferHelper - vm.prank(address(buyer)); - weth.approve(address(erc20TransferHelper), 50 ether); - } - - function runERC20() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(weth)); - - vm.prank(address(buyer)); - asks.fillAsk(address(token), 0, 1 ether, address(weth)); - } - - function test_ERC20Integration() public { - uint256 beforeBuyerBalance = weth.balanceOf(address(buyer)); - uint256 beforeSellerBalance = weth.balanceOf(address(seller)); - uint256 beforeRoyaltyRecipientBalance = weth.balanceOf(address(royaltyRecipient)); - uint256 beforeProtocolFeeRecipientBalance = weth.balanceOf(address(protocolFeeRecipient)); - address beforeTokenOwner = token.ownerOf(0); - - runERC20(); - - uint256 afterBuyerBalance = weth.balanceOf(address(buyer)); - uint256 afterSellerBalance = weth.balanceOf(address(seller)); - uint256 afterRoyaltyRecipientBalance = weth.balanceOf(address(royaltyRecipient)); - uint256 afterProtocolFeeRecipientBalance = weth.balanceOf(address(protocolFeeRecipient)); - address afterTokenOwner = token.ownerOf(0); - - // 1 ETH withdrawn from buyer - require((beforeBuyerBalance - afterBuyerBalance) == 1 ether); - // 0.05 ETH creator royalty - require((afterRoyaltyRecipientBalance - beforeRoyaltyRecipientBalance) == 0.05 ether); - // 1 bps protocol fee (Remaining 0.95 ETH * 0.01% protocol fee = 0.000095 ETH) - require((afterProtocolFeeRecipientBalance - beforeProtocolFeeRecipientBalance) == 0.000095 ether); - // Remaining 0.949905 ETH paid to seller - require((afterSellerBalance - beforeSellerBalance) == 0.949905 ether); - // NFT transferred to buyer - require(beforeTokenOwner == address(seller) && afterTokenOwner == address(buyer)); - } -} diff --git a/contracts/test/modules/Asks/Core/ERC20/AsksCoreErc20.t.sol b/contracts/test/modules/Asks/Core/ERC20/AsksCoreErc20.t.sol deleted file mode 100644 index e3596165..00000000 --- a/contracts/test/modules/Asks/Core/ERC20/AsksCoreErc20.t.sol +++ /dev/null @@ -1,362 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {AsksCoreErc20} from "../../../../../modules/Asks/Core/ERC20/AsksCoreErc20.sol"; -import {Zorb} from "../../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../../utils/modules/RoyaltyEngine.sol"; - -import {TestERC721} from "../../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../../utils/tokens/WETH.sol"; -import {VM} from "../../../../utils/VM.sol"; - -/// @title AsksCoreErc20Test -/// @notice Unit Tests for Asks Core ERC-20 -contract AsksCoreErc20Test is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - AsksCoreErc20 internal asks; - TestERC721 internal token; - WETH internal weth; - - Zorb internal seller; - Zorb internal operator; - Zorb internal otherSeller; - Zorb internal buyer; - Zorb internal finder; - Zorb internal sellerFundsRecipient; - Zorb internal royaltyRecipient; - - function setUp() public { - // Cheatcodes - vm = VM(HEVM_ADDRESS); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - seller = new Zorb(address(ZMM)); - operator = new Zorb(address(ZMM)); - otherSeller = new Zorb(address(ZMM)); - buyer = new Zorb(address(ZMM)); - finder = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - token = new TestERC721(); - weth = new WETH(); - - // Deploy Asks Core ERC-20 - asks = new AsksCoreErc20(address(erc20TransferHelper), address(erc721TransferHelper), address(royaltyEngine), address(ZPFS), address(weth)); - registrar.registerModule(address(asks)); - - // Set buyer balance - vm.deal(address(buyer), 100 ether); - - // Mint seller token - token.mint(address(seller), 0); - - // Buyer swap 50 ETH <> 50 WETH - vm.prank(address(buyer)); - weth.deposit{value: 50 ether}(); - - // Users approve Asks module - seller.setApprovalForModule(address(asks), true); - buyer.setApprovalForModule(address(asks), true); - - // Seller approve ERC721TransferHelper - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - - // Buyer approve ERC20TransferHelper - vm.prank(address(buyer)); - weth.approve(address(erc20TransferHelper), 50 ether); - } - - /// ------------ CREATE ASK ------------ /// - - function testGas_CreateAsk() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(weth)); - } - - function test_CreateAsk() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(weth)); - - (address askSeller, uint256 askPrice, address askCurrency) = asks.askForNFT(address(token), 0); - - require(askSeller == address(seller)); - require(askPrice == 1 ether); - require(askCurrency == address(weth)); - } - - function test_CreateAskFromTokenOperator() public { - vm.prank(address(seller)); - token.setApprovalForAll(address(operator), true); - - operator.setApprovalForModule(address(asks), true); - - vm.prank(address(operator)); - asks.createAsk(address(token), 0, 0.5 ether, address(weth)); - - (address askSeller, uint256 askPrice, address currency) = asks.askForNFT(address(token), 0); - - require(askSeller == address(seller)); - require(askPrice == 0.5 ether); - require(currency == address(weth)); - } - - function test_CreateAskAndOverridePrevious() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(weth)); - - (address askSeller, , ) = asks.askForNFT(address(token), 0); - - require(askSeller == address(seller)); - - vm.prank(address(seller)); - token.safeTransferFrom(address(seller), address(otherSeller), 0); - require(token.ownerOf(0) == address(otherSeller)); - - otherSeller.setApprovalForModule(address(asks), true); - - vm.prank(address(otherSeller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - - vm.prank(address(otherSeller)); - asks.createAsk(address(token), 0, 10 ether, address(weth)); - - (address newAskSeller, uint256 askPrice, ) = asks.askForNFT(address(token), 0); - - require(newAskSeller == address(otherSeller)); - require(askPrice == 10 ether); - } - - function test_CreateMaxAskPrice() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 2**96 - 1, address(weth)); - - (, uint256 askPrice, ) = asks.askForNFT(address(token), 0); - - require(askPrice == 2**96 - 1); - } - - function testRevert_MustBeOwnerOrOperator() public { - vm.expectRevert("ONLY_TOKEN_OWNER_OR_OPERATOR"); - asks.createAsk(address(token), 0, 1 ether, address(weth)); - } - - function testRevert_MaxAskPrice() public { - vm.prank(address(seller)); - vm.expectRevert("INVALID_ASK_PRICE"); - asks.createAsk(address(token), 0, 2**96, address(weth)); - } - - /// ------------ SET ASK PRICE ------------ /// - - function test_IncreaseAskPrice() public { - vm.startPrank(address(seller)); - - asks.createAsk(address(token), 0, 1 ether, address(weth)); - asks.setAskPrice(address(token), 0, 5 ether, address(weth)); - - vm.stopPrank(); - - (, uint256 askPrice, ) = asks.askForNFT(address(token), 0); - require(askPrice == 5 ether); - } - - function test_DecreaseAskPrice() public { - vm.startPrank(address(seller)); - - asks.createAsk(address(token), 0, 1 ether, address(weth)); - asks.setAskPrice(address(token), 0, 0.5 ether, address(weth)); - - vm.stopPrank(); - - (, uint256 askPrice, ) = asks.askForNFT(address(token), 0); - require(askPrice == 0.5 ether); - } - - function test_UpdateAskCurrency() public { - vm.startPrank(address(seller)); - - asks.createAsk(address(token), 0, 1 ether, address(weth)); - asks.setAskPrice(address(token), 0, 1 ether, address(0)); - - vm.stopPrank(); - - (, , address askCurrency) = asks.askForNFT(address(token), 0); - require(askCurrency == address(0)); - } - - function testRevert_OnlySellerCanSetAskPrice() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(weth)); - - vm.expectRevert("ONLY_SELLER"); - asks.setAskPrice(address(token), 0, 5 ether, address(weth)); - } - - function testRevert_CannotUpdateCanceledAsk() public { - vm.startPrank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(weth)); - asks.cancelAsk(address(token), 0); - - vm.expectRevert("ONLY_SELLER"); - asks.setAskPrice(address(token), 0, 5 ether, address(weth)); - vm.stopPrank(); - } - - function testRevert_CannotUpdateFilledAsk() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(weth)); - - vm.prank(address(buyer)); - asks.fillAsk{value: 1 ether}(address(token), 0, 1 ether, address(weth)); - - vm.prank(address(seller)); - vm.expectRevert("ONLY_SELLER"); - asks.setAskPrice(address(token), 0, 5 ether, address(weth)); - } - - function testRevert_CannotUpdateInvalidPrice() public { - vm.startPrank(address(seller)); - - asks.createAsk(address(token), 0, 1 ether, address(weth)); - - vm.warp(1 minutes); - - vm.expectRevert("INVALID_ASK_PRICE"); - asks.setAskPrice(address(token), 0, 2**96, address(weth)); - - vm.stopPrank(); - } - - /// ------------ CANCEL ASK ------------ /// - - function test_CancelAskSeller() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(weth)); - - (, uint256 beforeAskPrice, ) = asks.askForNFT(address(token), 0); - require(beforeAskPrice == 1 ether); - - vm.prank(address(seller)); - asks.cancelAsk(address(token), 0); - - (, uint256 afterAskPrice, ) = asks.askForNFT(address(token), 0); - require(afterAskPrice == 0); - } - - function test_CancelAskOwner() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(weth)); - - vm.prank(address(seller)); - token.transferFrom(address(seller), address(otherSeller), 0); - - vm.prank(address(seller)); - asks.cancelAsk(address(token), 0); - - (address askSeller, uint256 askPrice, ) = asks.askForNFT(address(token), 0); - - require(askSeller == address(0)); - require(askPrice == 0); - } - - function testRevert_MustBeSellerOrOwner() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(weth)); - - vm.expectRevert("ONLY_SELLER_OR_TOKEN_OWNER"); - asks.cancelAsk(address(token), 0); - } - - /// ------------ FILL ASK ------------ /// - - function test_FillAsk() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(weth)); - - vm.prank(address(buyer)); - asks.fillAsk(address(token), 0, 1 ether, address(weth)); - - require(token.ownerOf(0) == address(buyer)); - } - - function testRevert_MustApproveModule() public { - seller.setApprovalForModule(address(asks), false); - - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(weth)); - - vm.prank(address(buyer)); - vm.expectRevert("module has not been approved by user"); - asks.fillAsk(address(token), 0, 1 ether, address(weth)); - } - - function testRevert_MustApproveERC721TransferHelper() public { - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), false); - - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(weth)); - - vm.prank(address(buyer)); - vm.expectRevert("ERC721: transfer caller is not owner nor approved"); - asks.fillAsk(address(token), 0, 1 ether, address(weth)); - } - - function testRevert_AskMustBeActiveToFill() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(weth)); - - vm.prank(address(buyer)); - asks.fillAsk{value: 1 ether}(address(token), 0, 1 ether, address(weth)); - - vm.expectRevert("INACTIVE_ASK"); - asks.fillAsk{value: 1 ether}(address(token), 0, 1 ether, address(weth)); - } - - function testRevert_PriceMismatch() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(weth)); - - vm.prank(address(buyer)); - vm.expectRevert("MUST_MATCH_PRICE"); - asks.fillAsk(address(token), 0, 0.5 ether, address(weth)); - } - - function testRevert_CurrencyMismatch() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(weth)); - - vm.prank(address(buyer)); - vm.expectRevert("MUST_MATCH_CURRENCY"); - asks.fillAsk(address(token), 0, 1 ether, address(0)); - } -} diff --git a/contracts/test/modules/Asks/Core/ETH/AsksCoreEth.integration.t.sol b/contracts/test/modules/Asks/Core/ETH/AsksCoreEth.integration.t.sol deleted file mode 100644 index d82f1bd5..00000000 --- a/contracts/test/modules/Asks/Core/ETH/AsksCoreEth.integration.t.sol +++ /dev/null @@ -1,136 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {AsksCoreEth} from "../../../../../modules/Asks/Core/ETH/AsksCoreEth.sol"; -import {Zorb} from "../../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../../utils/modules/RoyaltyEngine.sol"; - -import {TestERC721} from "../../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../../utils/tokens/WETH.sol"; -import {VM} from "../../../../utils/VM.sol"; - -/// @title AsksCoreEthIntegrationTest -/// @notice Integration Tests for Asks Core ETH -contract AsksCoreEthIntegrationTest is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - AsksCoreEth internal asks; - TestERC721 internal token; - WETH internal weth; - - Zorb internal seller; - Zorb internal operator; - Zorb internal buyer; - Zorb internal finder; - Zorb internal sellerFundsRecipient; - Zorb internal royaltyRecipient; - Zorb internal protocolFeeRecipient; - - function setUp() public { - // Cheatcodes - vm = VM(HEVM_ADDRESS); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - seller = new Zorb(address(ZMM)); - operator = new Zorb(address(ZMM)); - buyer = new Zorb(address(ZMM)); - finder = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - protocolFeeRecipient = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - token = new TestERC721(); - weth = new WETH(); - - // Deploy Asks Core ETH - asks = new AsksCoreEth(address(erc721TransferHelper), address(royaltyEngine), address(ZPFS), address(weth)); - registrar.registerModule(address(asks)); - - // Set module fee - vm.prank(address(registrar)); - ZPFS.setFeeParams(address(asks), address(protocolFeeRecipient), 1); - - // Set buyer balance - vm.deal(address(buyer), 100 ether); - - // Mint seller token - token.mint(address(seller), 0); - - // Buyer swap 50 ETH <> 50 WETH - vm.prank(address(buyer)); - weth.deposit{value: 50 ether}(); - - // Users approve Asks module - seller.setApprovalForModule(address(asks), true); - buyer.setApprovalForModule(address(asks), true); - - // Seller approve ERC721TransferHelper - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - - // Buyer approve ERC20TransferHelper - vm.prank(address(buyer)); - weth.approve(address(erc20TransferHelper), 50 ether); - } - - function runETH() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether); - - vm.prank(address(buyer)); - asks.fillAsk{value: 1 ether}(address(token), 0); - } - - function test_ETHIntegration() public { - uint256 beforeBuyerBalance = address(buyer).balance; - uint256 beforeSellerBalance = address(seller).balance; - uint256 beforeRoyaltyRecipientBalance = address(royaltyRecipient).balance; - uint256 beforeProtocolFeeRecipientBalance = address(protocolFeeRecipient).balance; - address beforeTokenOwner = token.ownerOf(0); - - runETH(); - - uint256 afterBuyerBalance = address(buyer).balance; - uint256 afterSellerBalance = address(seller).balance; - uint256 afterRoyaltyRecipientBalance = address(royaltyRecipient).balance; - uint256 afterProtocolFeeRecipientBalance = address(protocolFeeRecipient).balance; - address afterTokenOwner = token.ownerOf(0); - - // 1 ETH withdrawn from buyer - require((beforeBuyerBalance - afterBuyerBalance) == 1 ether); - // 0.05 ETH creator royalty - require((afterRoyaltyRecipientBalance - beforeRoyaltyRecipientBalance) == 0.05 ether); - // 1 bps protocol fee (Remaining 0.95 ETH * 0.01% protocol fee = 0.000095 ETH) - require((afterProtocolFeeRecipientBalance - beforeProtocolFeeRecipientBalance) == 0.000095 ether); - // Remaining 0.949905 ETH paid to seller - require((afterSellerBalance - beforeSellerBalance) == 0.949905 ether); - // NFT transferred to buyer - require(beforeTokenOwner == address(seller) && afterTokenOwner == address(buyer)); - } -} diff --git a/contracts/test/modules/Asks/Core/ETH/AsksCoreEth.t.sol b/contracts/test/modules/Asks/Core/ETH/AsksCoreEth.t.sol deleted file mode 100644 index 13790be2..00000000 --- a/contracts/test/modules/Asks/Core/ETH/AsksCoreEth.t.sol +++ /dev/null @@ -1,322 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {AsksCoreEth} from "../../../../../modules/Asks/Core/ETH/AsksCoreEth.sol"; -import {Zorb} from "../../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../../utils/modules/RoyaltyEngine.sol"; -import {TestERC721} from "../../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../../utils/tokens/WETH.sol"; -import {VM} from "../../../../utils/VM.sol"; - -/// @title AsksCoreETHTest -/// @notice Unit Tests for Asks Core ETH -contract AsksCoreEthTest is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - AsksCoreEth internal asks; - WETH internal weth; - TestERC721 internal token; - - Zorb internal seller; - Zorb internal sellerFundsRecipient; - Zorb internal operator; - Zorb internal otherSeller; - Zorb internal buyer; - Zorb internal otherBuyer; - Zorb internal finder; - Zorb internal royaltyRecipient; - - function setUp() public { - // Cheatcodes - vm = VM(HEVM_ADDRESS); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - seller = new Zorb(address(ZMM)); - sellerFundsRecipient = new Zorb(address(ZMM)); - operator = new Zorb(address(ZMM)); - otherSeller = new Zorb(address(ZMM)); - buyer = new Zorb(address(ZMM)); - otherBuyer = new Zorb(address(ZMM)); - finder = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - token = new TestERC721(); - weth = new WETH(); - - // Deploy Asks Core ETH - asks = new AsksCoreEth(address(erc721TransferHelper), address(royaltyEngine), address(ZPFS), address(weth)); - registrar.registerModule(address(asks)); - - // Set user balances - vm.deal(address(buyer), 100 ether); - vm.deal(address(otherBuyer), 100 ether); - - // Mint seller tokens - token.mint(address(seller), 0); - - // Users approve Asks module - seller.setApprovalForModule(address(asks), true); - buyer.setApprovalForModule(address(asks), true); - - // Seller approve ERC721TransferHelper - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - - // Buyer approve ERC20TransferHelper - vm.prank(address(buyer)); - weth.approve(address(erc20TransferHelper), 50 ether); - } - - /// ------------ CREATE ASK ------------ /// - - function testGas_CreateAsk() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether); - } - - function test_CoreETHCreateAsk() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether); - - (address askSeller, uint256 askPrice) = asks.askForNFT(address(token), 0); - - require(askSeller == address(seller)); - require(askPrice == 1 ether); - } - - function test_CreateAskFromTokenOperator() public { - vm.prank(address(seller)); - token.setApprovalForAll(address(operator), true); - - operator.setApprovalForModule(address(asks), true); - - vm.prank(address(operator)); - asks.createAsk(address(token), 0, 0.5 ether); - - (address askSeller, uint256 askPrice) = asks.askForNFT(address(token), 0); - - require(askSeller == address(seller)); - require(askPrice == 0.5 ether); - } - - function test_CreateAskAndOverridePrevious() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether); - - (address askSeller, ) = asks.askForNFT(address(token), 0); - - require(askSeller == address(seller)); - - vm.prank(address(seller)); - token.safeTransferFrom(address(seller), address(otherSeller), 0); - require(token.ownerOf(0) == address(otherSeller)); - - otherSeller.setApprovalForModule(address(asks), true); - - vm.prank(address(otherSeller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - - vm.prank(address(otherSeller)); - asks.createAsk(address(token), 0, 10 ether); - - (address newAskSeller, uint256 askPrice) = asks.askForNFT(address(token), 0); - - require(newAskSeller == address(otherSeller)); - require(askPrice == 10 ether); - } - - function test_CreateMaxAskPrice() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 2**96 - 1); - - (, uint256 askPrice) = asks.askForNFT(address(token), 0); - - require(askPrice == 2**96 - 1); - } - - function testRevert_MustBeOwnerOrOperator() public { - vm.expectRevert("ONLY_TOKEN_OWNER_OR_OPERATOR"); - asks.createAsk(address(token), 0, 1 ether); - } - - /// ------------ SET ASK PRICE ------------ /// - - function test_IncreaseAskPrice() public { - vm.startPrank(address(seller)); - - asks.createAsk(address(token), 0, 1 ether); - asks.setAskPrice(address(token), 0, 5 ether); - - vm.stopPrank(); - - (, uint256 askPrice) = asks.askForNFT(address(token), 0); - require(askPrice == 5 ether); - } - - function test_DecreaseAskPrice() public { - vm.startPrank(address(seller)); - - asks.createAsk(address(token), 0, 1 ether); - asks.setAskPrice(address(token), 0, 0.5 ether); - - vm.stopPrank(); - - (, uint256 askPrice) = asks.askForNFT(address(token), 0); - require(askPrice == 0.5 ether); - } - - function testRevert_OnlySellerCanSetAskPrice() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether); - - vm.expectRevert("ONLY_SELLER"); - asks.setAskPrice(address(token), 0, 5 ether); - } - - function testRevert_CannotUpdateCanceledAsk() public { - vm.startPrank(address(seller)); - - asks.createAsk(address(token), 0, 1 ether); - - asks.cancelAsk(address(token), 0); - - vm.expectRevert("ONLY_SELLER"); - asks.setAskPrice(address(token), 0, 5 ether); - - vm.stopPrank(); - } - - function testRevert_CannotUpdateFilledAsk() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether); - - vm.prank(address(buyer)); - asks.fillAsk{value: 1 ether}(address(token), 0); - - vm.prank(address(seller)); - vm.expectRevert("ONLY_SELLER"); - asks.setAskPrice(address(token), 0, 5 ether); - } - - /// ------------ CANCEL ASK ------------ /// - - function test_CancelAskSeller() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether); - - (, uint256 beforeAskPrice) = asks.askForNFT(address(token), 0); - require(beforeAskPrice == 1 ether); - - vm.prank(address(seller)); - asks.cancelAsk(address(token), 0); - - (, uint256 afterAskPrice) = asks.askForNFT(address(token), 0); - require(afterAskPrice == 0); - } - - function test_CancelAskOwner() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether); - - vm.prank(address(seller)); - token.transferFrom(address(seller), address(otherSeller), 0); - - vm.prank(address(otherSeller)); - asks.cancelAsk(address(token), 0); - - (address askSeller, uint256 askPrice) = asks.askForNFT(address(token), 0); - - require(askSeller == address(0)); - require(askPrice == 0); - } - - function testRevert_MustBeSellerOrOwner() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether); - - vm.expectRevert("ONLY_SELLER_OR_TOKEN_OWNER"); - asks.cancelAsk(address(token), 0); - } - - /// ------------ FILL ASK ------------ /// - - function test_FillAsk() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether); - - vm.prank(address(buyer)); - asks.fillAsk{value: 1 ether}(address(token), 0); - - require(token.ownerOf(0) == address(buyer)); - } - - function testRevert_MustApproveModule() public { - seller.setApprovalForModule(address(asks), false); - - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether); - - vm.prank(address(buyer)); - vm.expectRevert("module has not been approved by user"); - asks.fillAsk{value: 1 ether}(address(token), 0); - } - - function testRevert_MustApproveERC721TransferHelper() public { - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), false); - - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether); - - vm.prank(address(buyer)); - vm.expectRevert("ERC721: transfer caller is not owner nor approved"); - asks.fillAsk{value: 1 ether}(address(token), 0); - } - - function testRevert_AskMustBeActiveToFill() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether); - - vm.prank(address(buyer)); - asks.fillAsk{value: 1 ether}(address(token), 0); - - vm.expectRevert("INACTIVE_ASK"); - asks.fillAsk{value: 1 ether}(address(token), 0); - } - - function testRevert_MustMeetPrice() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether); - - vm.prank(address(buyer)); - vm.expectRevert("MUST_MATCH_PRICE"); - asks.fillAsk{value: 0.99 ether}(address(token), 0); - } -} diff --git a/contracts/test/modules/Asks/Omnibus/AsksDataStorage.t.sol b/contracts/test/modules/Asks/Omnibus/AsksDataStorage.t.sol deleted file mode 100644 index e907937e..00000000 --- a/contracts/test/modules/Asks/Omnibus/AsksDataStorage.t.sol +++ /dev/null @@ -1,141 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {AsksDataStorage} from "../../../../modules/Asks/Omnibus/AsksDataStorage.sol"; -import {VM} from "../../../utils/VM.sol"; - -contract StorageTestBaseFull is AsksDataStorage { - function newAsk(address tokenContract, uint256 tokenId) public { - StoredAsk storage ask = askForNFT[tokenContract][tokenId]; - ask.seller = address(0x111); - ask.price = 0.4 ether; - _setERC20Currency(ask, address(0x113)); - _setTokenGate(ask, address(0x114), 0.1 ether); - _setListingFee(ask, 1, address(0x115)); - _setFindersFee(ask, 2); - _setExpiryAndFundsRecipient(ask, uint96(block.timestamp + 1_000), address(0x112)); - _setBuyer(ask, address(0x116)); - } - - function getExpectedActiveFeatures() public pure returns (uint32) { - return - FEATURE_MASK_LISTING_FEE | - FEATURE_MASK_FINDERS_FEE | - FEATURE_MASK_ERC20_CURRENCY | - FEATURE_MASK_TOKEN_GATE | - FEATURE_MASK_RECIPIENT_OR_EXPIRY | - FEATURE_MASK_BUYER; - } - - function hasFeature( - address tokenContract, - uint256 tokenId, - uint32 feature - ) public view returns (bool) { - StoredAsk storage ask = askForNFT[tokenContract][tokenId]; - return _hasFeature(ask.features, feature); - } - - function getFullAsk(address tokenContract, uint256 tokenId) public view returns (FullAsk memory) { - return _getFullAsk(askForNFT[tokenContract][tokenId]); - } - - function updatePrice( - address tokenContract, - uint256 tokenId, - address currency, - uint256 price - ) public { - StoredAsk storage ask = askForNFT[tokenContract][tokenId]; - _setETHorERC20Currency(ask, currency); - ask.price = price; - } -} - -contract StorageTestBaseMinimal is AsksDataStorage { - function newAsk(address tokenContract, uint256 tokenId) public { - StoredAsk storage ask = askForNFT[tokenContract][tokenId]; - ask.seller = address(0x111); - ask.price = 0.4 ether; - ask.features = 0; - } - - function getExpectedActiveFeatures() public pure returns (uint32) { - return 0; - } - - function hasFeature( - address tokenContract, - uint256 tokenId, - uint32 feature - ) public view returns (bool) { - StoredAsk storage ask = askForNFT[tokenContract][tokenId]; - return _hasFeature(ask.features, feature); - } - - function getFullAsk(address tokenContract, uint256 tokenId) public view returns (FullAsk memory) { - return _getFullAsk(askForNFT[tokenContract][tokenId]); - } -} - -/// @title -/// @notice -contract AsksDataStorageTest is DSTest { - VM internal vm; - - uint32 constant FEATURE_MASK_LISTING_FEE = 1 << 3; - uint32 constant FEATURE_MASK_FINDERS_FEE = 1 << 4; - uint32 constant FEATURE_MASK_ERC20_CURRENCY = 1 << 5; - uint32 constant FEATURE_MASK_TOKEN_GATE = 1 << 6; - uint32 constant FEATURE_MASK_RECIPIENT_OR_EXPIRY = 1 << 7; - uint32 constant FEATURE_MASK_BUYER = 1 << 8; - - function test_AskStorageMinimalInit() public { - StorageTestBaseMinimal dataStorage = new StorageTestBaseMinimal(); - dataStorage.newAsk(address(0x112), 21); - AsksDataStorage.FullAsk memory ask = dataStorage.getFullAsk(address(0x112), 21); - assertEq(ask.seller, address(0x111), "seller wrong"); - assertEq(ask.price, 0.4 ether, "price wrong"); - assertEq(ask.sellerFundsRecipient, address(0), "seller funds recipient wrong"); - assertEq(ask.currency, address(0), "incorrect currency"); - assertEq(ask.buyer, address(0), "incorrect buyer"); - assertEq(ask.expiry, 0, "incorrect expiry"); - assertEq(ask.findersFeeBps, 0, "incorrect finders fee"); - assertEq(ask.tokenGateToken, address(0), "incorrect token gate"); - assertEq(ask.tokenGateMinAmount, 0, "incorrect token gate"); - assertEq(ask.listingFeeBps, 0, "incorrect listing fee"); - assertEq(ask.listingFeeRecipient, address(0), "incorrect listing fee"); - } - - function test_AskStorageInit() public { - StorageTestBaseFull dataStorage = new StorageTestBaseFull(); - dataStorage.newAsk(address(0x121), 21); - AsksDataStorage.FullAsk memory ask = dataStorage.getFullAsk(address(0x121), 21); - assertEq(ask.seller, address(0x111), "seller wrong"); - assertEq(ask.price, 0.4 ether, "price wrong"); - assertEq(ask.sellerFundsRecipient, address(0x112), "seller funds recipient wrong"); - assertEq(ask.currency, address(0x113), "incorrect currency"); - assertEq(ask.buyer, address(0x116), "incorrect buyer"); - assertEq(ask.expiry, block.timestamp + 1_000, "incorrect expiry"); - assertEq(ask.findersFeeBps, 2, "incorrect finders fee"); - assertEq(ask.tokenGateToken, address(0x114), "incorrect token gate"); - assertEq(ask.tokenGateMinAmount, 0.1 ether, "incorrect token gate"); - assertEq(ask.listingFeeBps, 1, "incorrect listing fee"); - assertEq(ask.listingFeeRecipient, address(0x115), "incorrect listing fee"); - } - - function test_AskStorageUpdatePrice() public { - StorageTestBaseFull dataStorage = new StorageTestBaseFull(); - dataStorage.newAsk(address(0x121), 21); - AsksDataStorage.FullAsk memory ask = dataStorage.getFullAsk(address(0x121), 21); - assertEq(ask.price, 0.4 ether, "price wrong"); - assertEq(ask.currency, address(0x113), "incorrect currency"); - dataStorage.updatePrice(address(0x121), 21, address(0), 1 ether); - ask = dataStorage.getFullAsk(address(0x121), 21); - assertEq(ask.price, 1 ether, "price wrong"); - assertEq(ask.currency, address(0), "incorrect currency"); - assertTrue(!dataStorage.hasFeature(address(0x121), 21, FEATURE_MASK_ERC20_CURRENCY)); - } -} diff --git a/contracts/test/modules/Asks/Omnibus/AsksOmnibus.t.sol b/contracts/test/modules/Asks/Omnibus/AsksOmnibus.t.sol deleted file mode 100644 index c6581b0f..00000000 --- a/contracts/test/modules/Asks/Omnibus/AsksOmnibus.t.sol +++ /dev/null @@ -1,636 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {AsksOmnibus} from "../../../../modules/Asks/Omnibus/AsksOmnibus.sol"; -import {AsksDataStorage} from "../../../../modules/Asks/Omnibus/AsksDataStorage.sol"; -import {Zorb} from "../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../utils/modules/RoyaltyEngine.sol"; -import {TestERC20} from "../../../utils/tokens/TestERC20.sol"; -import {TestERC721} from "../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../utils/tokens/WETH.sol"; -import {VM} from "../../../utils/VM.sol"; - -/// @title ReserveAuctionFindersErc20Test -/// @notice Unit Tests for Reserve Auction Finders ERC-20 -contract AsksOmnibusTest is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - AsksOmnibus internal asks; - TestERC20 internal erc20; - TestERC721 internal token; - WETH internal weth; - - Zorb internal seller; - Zorb internal sellerFundsRecipient; - Zorb internal operator; - Zorb internal finder; - Zorb internal listingFeeRecipient; - Zorb internal royaltyRecipient; - Zorb internal buyer; - Zorb internal other; - - function setUp() public { - // Cheatcodes - vm = VM(HEVM_ADDRESS); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - seller = new Zorb(address(ZMM)); - sellerFundsRecipient = new Zorb(address(ZMM)); - operator = new Zorb(address(ZMM)); - buyer = new Zorb(address(ZMM)); - finder = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - listingFeeRecipient = new Zorb(address(ZMM)); - other = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - erc20 = new TestERC20(); - token = new TestERC721(); - weth = new WETH(); - - // Deploy Asks Omnibus - asks = new AsksOmnibus(address(erc20TransferHelper), address(erc721TransferHelper), address(royaltyEngine), address(ZPFS), address(weth)); - registrar.registerModule(address(asks)); - - // Set balances - vm.deal(address(seller), 100 ether); - vm.deal(address(buyer), 100 ether); - - // Mint seller token - token.mint(address(seller), 0); - - // Mint bidder 2^96 ERC-20 tokens - erc20.mint(address(buyer), 2**96); - - // Bidder swap 50 ETH <> 50 WETH - vm.prank(address(buyer)); - weth.deposit{value: 50 ether}(); - - // Users approve AsksOmnibus module - seller.setApprovalForModule(address(asks), true); - buyer.setApprovalForModule(address(asks), true); - - // Seller approve ERC721TransferHelper - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - - // Bidder approve ERC20TransferHelper for TestERC20 - vm.prank(address(buyer)); - erc20.approve(address(erc20TransferHelper), 2**96); - - // Bidder approve ERC20TransferHelper for WETH - vm.prank(address(buyer)); - weth.approve(address(erc20TransferHelper), 50 ether); - } - - /// ------------ CREATE ASK ------------ /// - - function test_CreateAskMinimal() public { - vm.prank(address(seller)); - asks.createAskMinimal(address(token), 0, 1 ether); - AsksDataStorage.FullAsk memory ask = asks.getFullAsk(address(token), 0); - assertEq(ask.seller, address(seller)); - assertEq(ask.sellerFundsRecipient, address(0)); - assertEq(ask.currency, address(0)); - assertEq(ask.buyer, address(0)); - assertEq(ask.expiry, 0); - assertEq(ask.findersFeeBps, 0); - assertEq(ask.price, 1 ether); - assertEq(ask.tokenGateToken, address(0)); - assertEq(ask.tokenGateMinAmount, 0); - assertEq(ask.listingFeeBps, 0); - assertEq(ask.listingFeeRecipient, address(0)); - } - - function testRevert_CreateAskMinimalNotTokenOwnerOrOperator() public { - vm.prank(address(other)); - vm.expectRevert(abi.encodeWithSignature("NOT_TOKEN_OWNER_OR_OPERATOR()")); - asks.createAskMinimal(address(token), 0, 1 ether); - } - - function testRevert_CreateAskMinimalModuleNotApproved() public { - vm.startPrank(address(seller)); - seller.setApprovalForModule(address(asks), false); - vm.expectRevert(abi.encodeWithSignature("MODULE_NOT_APPROVED()")); - asks.createAskMinimal(address(token), 0, 1 ether); - vm.stopPrank(); - } - - function testRevert_CreateAskMinimalTransferHelperNotApproved() public { - vm.startPrank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), false); - vm.expectRevert(abi.encodeWithSignature("TRANSFER_HELPER_NOT_APPROVED()")); - asks.createAskMinimal(address(token), 0, 1 ether); - vm.stopPrank(); - } - - function test_CreateAsk() public { - vm.prank(address(seller)); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 1000, - 1, - address(listingFeeRecipient), - address(erc20), - 1 - ); - AsksDataStorage.FullAsk memory ask = asks.getFullAsk(address(token), 0); - assertEq(ask.seller, address(seller)); - assertEq(ask.sellerFundsRecipient, address(sellerFundsRecipient)); - assertEq(ask.currency, address(weth)); - assertEq(ask.buyer, address(0)); - assertEq(ask.expiry, uint96(block.timestamp + 1 days)); - assertEq(ask.findersFeeBps, 1000); - assertEq(ask.price, 1 ether); - assertEq(ask.tokenGateToken, address(erc20)); - assertEq(ask.tokenGateMinAmount, 1); - assertEq(ask.listingFeeBps, 1); - assertEq(ask.listingFeeRecipient, address(listingFeeRecipient)); - } - - function testRevert_CreateAskNotTokenOwnerOrOperator() public { - vm.prank(address(other)); - vm.expectRevert(abi.encodeWithSignature("NOT_TOKEN_OWNER_OR_OPERATOR()")); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 1000, - 1, - address(listingFeeRecipient), - address(erc20), - 1 - ); - } - - function testRevert_CreateAskModuleNotApproved() public { - vm.startPrank(address(seller)); - seller.setApprovalForModule(address(asks), false); - vm.expectRevert(abi.encodeWithSignature("MODULE_NOT_APPROVED()")); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 1000, - 1, - address(listingFeeRecipient), - address(erc20), - 1 - ); - vm.stopPrank(); - } - - function testRevert_CreateAskTransferHelperNotApproved() public { - vm.startPrank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), false); - vm.expectRevert(abi.encodeWithSignature("TRANSFER_HELPER_NOT_APPROVED()")); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 1000, - 1, - address(listingFeeRecipient), - address(erc20), - 1 - ); - vm.stopPrank(); - } - - function testRevert_CreateAskInvalidListingFee() public { - vm.startPrank(address(seller)); - vm.expectRevert(abi.encodeWithSignature("INVALID_LISTING_FEE()")); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 1000, - 1, - address(0), - address(erc20), - 1 - ); - vm.expectRevert(abi.encodeWithSignature("INVALID_LISTING_FEE()")); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 1000, - 0, - address(sellerFundsRecipient), - address(erc20), - 1 - ); - vm.stopPrank(); - } - - function testRevert_CreateAskInvalidFees() public { - vm.startPrank(address(seller)); - vm.expectRevert(abi.encodeWithSignature("INVALID_FEES()")); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 5001, - 5000, - address(sellerFundsRecipient), - address(erc20), - 1 - ); - vm.expectRevert(abi.encodeWithSignature("INVALID_FEES()")); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 5000, - 5001, - address(sellerFundsRecipient), - address(erc20), - 1 - ); - vm.stopPrank(); - } - - function testRevert_CreateAskInvalidTokenGate() public { - vm.startPrank(address(seller)); - vm.expectRevert(abi.encodeWithSignature("INVALID_TOKEN_GATE()")); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 1, - 1, - address(other), - address(erc20), - 0 - ); - vm.expectRevert(abi.encodeWithSignature("INVALID_TOKEN_GATE()")); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 1, - 1, - address(other), - address(0), - 1 - ); - vm.stopPrank(); - } - - function testRevert_CreateAskInvalidExpiry() public { - vm.prank(address(seller)); - vm.warp(2 days); - vm.expectRevert(abi.encodeWithSignature("INVALID_EXPIRY()")); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp - 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 1, - 1, - address(other), - address(0), - 0 - ); - } - - /// ------------ FILL ASK ------------ /// - - function test_FillAsk() public { - vm.prank(address(seller)); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 1000, - 1, - address(listingFeeRecipient), - address(erc20), - 1 - ); - - vm.prank(address(buyer)); - asks.fillAsk(address(token), 0, 1 ether, address(weth), address(finder)); - - assertEq(weth.balanceOf(address(royaltyRecipient)), 0.05 ether); - assertEq(weth.balanceOf(address(finder)), 0.95 ether / 10); - assertEq(weth.balanceOf(address(listingFeeRecipient)), 0.95 ether / 10000); - assertEq(weth.balanceOf(address(sellerFundsRecipient)), 0.95 ether - (0.95 ether / 10) - (0.95 ether / 10000)); - assertEq(token.ownerOf(0), address(buyer)); - } - - function testRevert_FillAskInactive() public { - vm.prank(address(buyer)); - vm.expectRevert(abi.encodeWithSignature("ASK_INACTIVE()")); - asks.fillAsk(address(token), 0, 1 ether, address(weth), address(finder)); - } - - function testRevert_FillAskWrongCurrencyOrAmount() public { - vm.startPrank(address(seller)); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 1000, - 0, - address(0), - address(0), - 0 - ); - asks.setAskPrice(address(token), 0, 2 ether, address(erc20)); - vm.stopPrank(); - - vm.prank(address(buyer)); - vm.expectRevert(abi.encodeWithSignature("INCORRECT_CURRENCY_OR_AMOUNT()")); - asks.fillAsk(address(token), 0, 1 ether, address(weth), address(finder)); - } - - function testRevert_FillAskExpired() public { - vm.warp(1 days); - vm.prank(address(seller)); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 1000, - 0, - address(0), - address(0), - 0 - ); - - vm.warp(3 days); - vm.prank(address(buyer)); - vm.expectRevert(abi.encodeWithSignature("ASK_EXPIRED()")); - asks.fillAsk(address(token), 0, 1 ether, address(weth), address(finder)); - } - - function testRevert_FillAskTokenGateInsufficientBalance() public { - vm.prank(address(seller)); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 1000, - 0, - address(0), - address(erc20), - 1 - ); - - vm.prank(address(other)); - vm.expectRevert(abi.encodeWithSignature("TOKEN_GATE_INSUFFICIENT_BALANCE()")); - asks.fillAsk(address(token), 0, 1 ether, address(weth), address(finder)); - } - - function testRevert_FillAskNotPrivateBuyer() public { - vm.prank(address(seller)); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(other), - 1000, - 0, - address(0), - address(0), - 0 - ); - - vm.prank(address(buyer)); - vm.expectRevert(abi.encodeWithSignature("NOT_DESIGNATED_BUYER()")); - asks.fillAsk(address(token), 0, 1 ether, address(weth), address(finder)); - } - - /// ------------ SET PRICE ------------ /// - - function test_SetAskPrice() public { - vm.startPrank(address(seller)); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 1000, - 1, - address(listingFeeRecipient), - address(erc20), - 1 - ); - asks.setAskPrice(address(token), 0, 2 ether, address(weth)); - vm.stopPrank(); - - AsksDataStorage.FullAsk memory ask = asks.getFullAsk(address(token), 0); - assertEq(ask.seller, address(seller)); - assertEq(ask.sellerFundsRecipient, address(sellerFundsRecipient)); - assertEq(ask.currency, address(weth)); - assertEq(ask.buyer, address(0)); - assertEq(ask.expiry, uint96(block.timestamp + 1 days)); - assertEq(ask.findersFeeBps, 1000); - assertEq(ask.price, 2 ether); - assertEq(ask.tokenGateToken, address(erc20)); - assertEq(ask.tokenGateMinAmount, 1); - assertEq(ask.listingFeeBps, 1); - assertEq(ask.listingFeeRecipient, address(listingFeeRecipient)); - } - - function testRevert_SetAskPriceOnlyTokenOwnerOrOperator() public { - vm.prank(address(seller)); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 1000, - 1, - address(listingFeeRecipient), - address(erc20), - 1 - ); - vm.expectRevert(abi.encodeWithSignature("NOT_TOKEN_OWNER_OR_OPERATOR()")); - asks.setAskPrice(address(token), 0, 2 ether, address(weth)); - } - - /// ------------ CANCEL ASK ------------ /// - - function test_CancelAsk() public { - vm.startPrank(address(seller)); - - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 1000, - 1, - address(listingFeeRecipient), - address(erc20), - 1 - ); - - asks.cancelAsk(address(token), 0); - - AsksDataStorage.FullAsk memory ask = asks.getFullAsk(address(token), 0); - assertEq(ask.seller, address(0)); - assertEq(ask.sellerFundsRecipient, address(0)); - assertEq(ask.currency, address(0)); - assertEq(ask.buyer, address(0)); - assertEq(ask.expiry, 0); - assertEq(ask.findersFeeBps, 0); - assertEq(ask.price, 0); - assertEq(ask.tokenGateToken, address(0)); - assertEq(ask.tokenGateMinAmount, 0); - assertEq(ask.listingFeeBps, 0); - assertEq(ask.listingFeeRecipient, address(0)); - vm.stopPrank(); - - vm.startPrank(address(buyer)); - vm.expectRevert(abi.encodeWithSignature("ASK_INACTIVE()")); - asks.fillAsk(address(token), 0, 1 ether, address(weth), address(0)); - } - - function test_CancelAskAnyoneCanCallIfAskInvalid() public { - vm.startPrank(address(seller)); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 1000, - 1, - address(listingFeeRecipient), - address(erc20), - 1 - ); - token.safeTransferFrom(address(seller), address(other), 0); - vm.stopPrank(); - - vm.prank(address(buyer)); - asks.cancelAsk(address(token), 0); - } - - function testRevert_CancelAskOnlyTokenOwnerOrOperator() public { - vm.prank(address(seller)); - asks.createAsk( - address(token), - 0, - uint96(block.timestamp + 1 days), - 1 ether, - address(sellerFundsRecipient), - address(weth), - address(0), - 1000, - 1, - address(listingFeeRecipient), - address(erc20), - 1 - ); - - vm.prank(address(buyer)); - vm.expectRevert(abi.encodeWithSignature("NOT_TOKEN_OWNER_OR_OPERATOR()")); - asks.cancelAsk(address(token), 0); - } -} diff --git a/contracts/test/modules/Asks/Private/ETH/AsksPrivateEth.integration.t.sol b/contracts/test/modules/Asks/Private/ETH/AsksPrivateEth.integration.t.sol deleted file mode 100644 index 17dd24ab..00000000 --- a/contracts/test/modules/Asks/Private/ETH/AsksPrivateEth.integration.t.sol +++ /dev/null @@ -1,131 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {AsksPrivateEth} from "../../../../../modules/Asks/Private/ETH/AsksPrivateEth.sol"; -import {Zorb} from "../../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../../utils/modules/RoyaltyEngine.sol"; -import {TestERC721} from "../../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../../utils/tokens/WETH.sol"; -import {VM} from "../../../../utils/VM.sol"; - -/// @title AsksPrivateEthIntegrationTest -/// @notice Integration Tests for Asks Private ETH -contract AsksPrivateEthIntegrationTest is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - AsksPrivateEth internal asks; - TestERC721 internal token; - WETH internal weth; - - Zorb internal seller; - Zorb internal operator; - Zorb internal buyer; - Zorb internal finder; - Zorb internal sellerFundsRecipient; - Zorb internal royaltyRecipient; - Zorb internal protocolFeeRecipient; - - function setUp() public { - // Cheatcodes - vm = VM(HEVM_ADDRESS); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - seller = new Zorb(address(ZMM)); - operator = new Zorb(address(ZMM)); - buyer = new Zorb(address(ZMM)); - finder = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - protocolFeeRecipient = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - token = new TestERC721(); - weth = new WETH(); - - // Deploy Asks Private ETH - asks = new AsksPrivateEth(address(erc721TransferHelper), address(royaltyEngine), address(ZPFS), address(weth)); - registrar.registerModule(address(asks)); - - // Set module fee - vm.prank(address(registrar)); - ZPFS.setFeeParams(address(asks), address(protocolFeeRecipient), 1); - - // Set buyer balance - vm.deal(address(buyer), 100 ether); - - // Mint seller token - token.mint(address(seller), 0); - - // Buyer swap 50 ETH <> 50 WETH - vm.prank(address(buyer)); - weth.deposit{value: 50 ether}(); - - // Users approve Asks module - seller.setApprovalForModule(address(asks), true); - buyer.setApprovalForModule(address(asks), true); - - // Seller approve ERC721TransferHelper - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - } - - function runETH() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(buyer)); - - vm.prank(address(buyer)); - asks.fillAsk{value: 1 ether}(address(token), 0); - } - - function test_ETHIntegration() public { - uint256 beforeBuyerBalance = address(buyer).balance; - uint256 beforeSellerBalance = address(seller).balance; - uint256 beforeRoyaltyRecipientBalance = address(royaltyRecipient).balance; - uint256 beforeProtocolFeeRecipientBalance = address(protocolFeeRecipient).balance; - address beforeTokenOwner = token.ownerOf(0); - - runETH(); - - uint256 afterBuyerBalance = address(buyer).balance; - uint256 afterSellerBalance = address(seller).balance; - uint256 afterRoyaltyRecipientBalance = address(royaltyRecipient).balance; - uint256 afterProtocolFeeRecipientBalance = address(protocolFeeRecipient).balance; - address afterTokenOwner = token.ownerOf(0); - - // 1 ETH withdrawn from buyer - require((beforeBuyerBalance - afterBuyerBalance) == 1 ether); - // 0.05 ETH creator royalty - require((afterRoyaltyRecipientBalance - beforeRoyaltyRecipientBalance) == 0.05 ether); - // 1 bps protocol fee (Remaining 0.95 ETH * 0.01% protocol fee = 0.000095 ETH) - require((afterProtocolFeeRecipientBalance - beforeProtocolFeeRecipientBalance) == 0.000095 ether); - // Remaining 0.949905 ETH paid to seller - require((afterSellerBalance - beforeSellerBalance) == 0.949905 ether); - // NFT transferred to buyer - require(beforeTokenOwner == address(seller) && afterTokenOwner == address(buyer)); - } -} diff --git a/contracts/test/modules/Asks/Private/ETH/AsksPrivateEth.t.sol b/contracts/test/modules/Asks/Private/ETH/AsksPrivateEth.t.sol deleted file mode 100644 index 9b196311..00000000 --- a/contracts/test/modules/Asks/Private/ETH/AsksPrivateEth.t.sol +++ /dev/null @@ -1,333 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {AsksPrivateEth} from "../../../../../modules/Asks/Private/ETH/AsksPrivateEth.sol"; -import {Zorb} from "../../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../../utils/modules/RoyaltyEngine.sol"; -import {TestERC721} from "../../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../../utils/tokens/WETH.sol"; -import {VM} from "../../../../utils/VM.sol"; - -/// @title AsksPrivateEthTest -/// @notice Unit Tests for Asks Private ETH -contract AsksPrivateEthTest is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - AsksPrivateEth internal asks; - WETH internal weth; - TestERC721 internal token; - - Zorb internal seller; - Zorb internal sellerFundsRecipient; - Zorb internal operator; - Zorb internal otherSeller; - Zorb internal buyer; - Zorb internal otherBuyer; - Zorb internal finder; - Zorb internal royaltyRecipient; - - function setUp() public { - // Cheatcodes - vm = VM(HEVM_ADDRESS); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - seller = new Zorb(address(ZMM)); - sellerFundsRecipient = new Zorb(address(ZMM)); - operator = new Zorb(address(ZMM)); - otherSeller = new Zorb(address(ZMM)); - buyer = new Zorb(address(ZMM)); - otherBuyer = new Zorb(address(ZMM)); - finder = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - token = new TestERC721(); - weth = new WETH(); - - // Deploy Asks Private ETH - asks = new AsksPrivateEth(address(erc721TransferHelper), address(royaltyEngine), address(ZPFS), address(weth)); - registrar.registerModule(address(asks)); - - // Set user balances - vm.deal(address(buyer), 100 ether); - vm.deal(address(otherBuyer), 100 ether); - - // Mint seller tokens - token.mint(address(seller), 0); - - // Users approve Asks module - seller.setApprovalForModule(address(asks), true); - buyer.setApprovalForModule(address(asks), true); - - // Seller approve ERC721TransferHelper - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - } - - /// /// - /// CREATE ASK /// - /// /// - - function test_CreateAsk() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(buyer)); - - (address askSeller, uint256 askPrice, address askBuyer) = asks.askForNFT(address(token), 0); - - require(askSeller == address(seller)); - require(askPrice == 1 ether); - require(askBuyer == address(buyer)); - } - - function test_CreateAskFromTokenOperator() public { - vm.prank(address(seller)); - token.setApprovalForAll(address(operator), true); - - operator.setApprovalForModule(address(asks), true); - - vm.prank(address(operator)); - asks.createAsk(address(token), 0, 0.5 ether, address(buyer)); - - (address askSeller, uint256 askPrice, address askBuyer) = asks.askForNFT(address(token), 0); - - require(askSeller == address(seller)); - require(askPrice == 0.5 ether); - require(askBuyer == address(buyer)); - } - - function test_CreateAskAndOverridePrevious() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(buyer)); - - (address askSeller, , ) = asks.askForNFT(address(token), 0); - - require(askSeller == address(seller)); - - vm.prank(address(seller)); - token.safeTransferFrom(address(seller), address(otherSeller), 0); - require(token.ownerOf(0) == address(otherSeller)); - - otherSeller.setApprovalForModule(address(asks), true); - - vm.prank(address(otherSeller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - - vm.prank(address(otherSeller)); - asks.createAsk(address(token), 0, 10 ether, address(otherBuyer)); - - (address newAskSeller, uint256 askPrice, address newAskBuyer) = asks.askForNFT(address(token), 0); - - require(newAskSeller == address(otherSeller)); - require(askPrice == 10 ether); - require(newAskBuyer == address(otherBuyer)); - } - - function test_CreateMaxAskPrice() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 2**96 - 1, address(buyer)); - - (, uint256 askPrice, ) = asks.askForNFT(address(token), 0); - - require(askPrice == 2**96 - 1); - } - - function testRevert_MustBeOwnerOrOperator() public { - vm.expectRevert("ONLY_TOKEN_OWNER_OR_OPERATOR"); - asks.createAsk(address(token), 0, 1 ether, address(buyer)); - } - - /// /// - /// UPDATE ASK /// - /// /// - - function test_IncreaseAskPrice() public { - vm.startPrank(address(seller)); - - asks.createAsk(address(token), 0, 1 ether, address(buyer)); - asks.setAskPrice(address(token), 0, 5 ether); - - vm.stopPrank(); - - (, uint256 askPrice, ) = asks.askForNFT(address(token), 0); - require(askPrice == 5 ether); - } - - function test_DecreaseAskPrice() public { - vm.startPrank(address(seller)); - - asks.createAsk(address(token), 0, 1 ether, address(buyer)); - asks.setAskPrice(address(token), 0, 0.5 ether); - - vm.stopPrank(); - - (, uint256 askPrice, ) = asks.askForNFT(address(token), 0); - require(askPrice == 0.5 ether); - } - - function testRevert_OnlySellerCanSetAskPrice() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(buyer)); - - vm.expectRevert("ONLY_SELLER"); - asks.setAskPrice(address(token), 0, 5 ether); - } - - function testRevert_CannotUpdateCanceledAsk() public { - vm.startPrank(address(seller)); - - asks.createAsk(address(token), 0, 1 ether, address(buyer)); - - asks.cancelAsk(address(token), 0); - - vm.expectRevert("ONLY_SELLER"); - asks.setAskPrice(address(token), 0, 5 ether); - - vm.stopPrank(); - } - - function testRevert_CannotUpdateFilledAsk() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(buyer)); - - vm.prank(address(buyer)); - asks.fillAsk{value: 1 ether}(address(token), 0); - - vm.prank(address(seller)); - vm.expectRevert("ONLY_SELLER"); - asks.setAskPrice(address(token), 0, 5 ether); - } - - /// /// - /// CANCEL ASK /// - /// /// - - function test_CancelAskSeller() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(buyer)); - - (, uint256 beforeAskPrice, ) = asks.askForNFT(address(token), 0); - require(beforeAskPrice == 1 ether); - - vm.prank(address(seller)); - asks.cancelAsk(address(token), 0); - - (, uint256 afterAskPrice, ) = asks.askForNFT(address(token), 0); - require(afterAskPrice == 0); - } - - function test_CancelAskOwner() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(buyer)); - - vm.prank(address(seller)); - token.transferFrom(address(seller), address(otherSeller), 0); - - vm.prank(address(otherSeller)); - asks.cancelAsk(address(token), 0); - - (address askSeller, uint256 askPrice, address askBuyer) = asks.askForNFT(address(token), 0); - - require(askSeller == address(0)); - require(askPrice == 0); - require(askBuyer == address(0)); - } - - function testRevert_MustBeSellerOrOwner() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(buyer)); - - vm.expectRevert("ONLY_SELLER_OR_TOKEN_OWNER"); - asks.cancelAsk(address(token), 0); - } - - /// /// - /// FILL ASK /// - /// /// - - function test_FillAsk() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(buyer)); - - vm.prank(address(buyer)); - asks.fillAsk{value: 1 ether}(address(token), 0); - - require(token.ownerOf(0) == address(buyer)); - } - - function testRevert_OnlyBuyer() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(buyer)); - - vm.expectRevert("ONLY_BUYER"); - asks.fillAsk{value: 1 ether}(address(token), 0); - } - - function testRevert_MustApproveModule() public { - seller.setApprovalForModule(address(asks), false); - - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(buyer)); - - vm.prank(address(buyer)); - vm.expectRevert("module has not been approved by user"); - asks.fillAsk{value: 1 ether}(address(token), 0); - } - - function testRevert_MustApproveERC721TransferHelper() public { - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), false); - - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(buyer)); - - vm.prank(address(buyer)); - vm.expectRevert("ERC721: transfer caller is not owner nor approved"); - asks.fillAsk{value: 1 ether}(address(token), 0); - } - - function testRevert_AskMustBeActiveToFill() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(buyer)); - - vm.prank(address(buyer)); - asks.fillAsk{value: 1 ether}(address(token), 0); - - vm.expectRevert("INACTIVE_ASK"); - asks.fillAsk{value: 1 ether}(address(token), 0); - } - - function testRevert_MustMeetPrice() public { - vm.prank(address(seller)); - asks.createAsk(address(token), 0, 1 ether, address(buyer)); - - vm.prank(address(buyer)); - vm.expectRevert("PRICE_MISMATCH"); - asks.fillAsk{value: 0.99 ether}(address(token), 0); - } -} diff --git a/contracts/test/modules/Offers/Omnibus/OffersOmnibus.integration.t.sol b/contracts/test/modules/Offers/Omnibus/OffersOmnibus.integration.t.sol deleted file mode 100644 index 1e43c8bc..00000000 --- a/contracts/test/modules/Offers/Omnibus/OffersOmnibus.integration.t.sol +++ /dev/null @@ -1,172 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {OffersOmnibus} from "../../../../modules/Offers/Omnibus/OffersOmnibus.sol"; -import {OffersDataStorage} from "../../../../modules/Offers/Omnibus/OffersDataStorage.sol"; -import {Zorb} from "../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../utils/modules/RoyaltyEngine.sol"; - -import {TestERC721} from "../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../utils/tokens/WETH.sol"; -import {VM} from "../../../utils/VM.sol"; - -/// @title OffersV1IntegrationTest -/// @notice Integration Tests for Offers v1.0 -contract OffersOmnibusIntegrationTest is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - OffersOmnibus internal offers; - TestERC721 internal token; - WETH internal weth; - - Zorb internal seller; - Zorb internal buyer; - Zorb internal finder; - Zorb internal royaltyRecipient; - Zorb internal listingFeeRecipient; - - function setUp() public { - // Cheatcodes - vm = VM(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - seller = new Zorb(address(ZMM)); - buyer = new Zorb(address(ZMM)); - finder = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - listingFeeRecipient = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - token = new TestERC721(); - weth = new WETH(); - - // Deploy Offers v1.0 - offers = new OffersOmnibus(address(erc20TransferHelper), address(erc721TransferHelper), address(royaltyEngine), address(ZPFS), address(weth)); - registrar.registerModule(address(offers)); - - // Set buyer balance - vm.deal(address(buyer), 100 ether); - - // Mint buyer token - token.mint(address(seller), 0); - - // buyer swap 50 ETH <> 50 WETH - vm.prank(address(buyer)); - weth.deposit{value: 50 ether}(); - - // Users approve Offers module - buyer.setApprovalForModule(address(offers), true); - seller.setApprovalForModule(address(offers), true); - - // Buyer approve ERC20TransferHelper - vm.prank(address(buyer)); - weth.approve(address(erc20TransferHelper), 50 ether); - - // Seller approve ERC721TransferHelper - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - } - - /// ------------ ETH Offer ------------ /// - - function runETH() public { - vm.prank(address(buyer)); - uint256 id = offers.createOffer{value: 1 ether}(address(token), 0, address(0), 1 ether, 0, 100, 200, address(listingFeeRecipient)); - - vm.prank(address(seller)); - offers.fillOffer(address(token), 0, id, 1 ether, address(0), address(finder)); - } - - function test_ETHIntegration() public { - uint256 beforeSellerBalance = address(seller).balance; - uint256 beforeBuyerBalance = address(buyer).balance; - uint256 beforeRoyaltyRecipientBalance = address(royaltyRecipient).balance; - uint256 beforeFinderBalance = address(finder).balance; - uint256 beforeListingFeeRecipientBalance = address(listingFeeRecipient).balance; - address beforeTokenOwner = token.ownerOf(0); - runETH(); - uint256 afterSellerBalance = address(seller).balance; - uint256 afterBuyerBalance = address(buyer).balance; - uint256 afterRoyaltyRecipientBalance = address(royaltyRecipient).balance; - uint256 afterFinderBalance = address(finder).balance; - uint256 afterListingFeeRecipientBalance = address(listingFeeRecipient).balance; - address afterTokenOwner = token.ownerOf(0); - // 1 ETH withdrawn from buyer - require((beforeBuyerBalance - afterBuyerBalance) == 1 ether); - // 0.05 ETH creator royalty - require((afterRoyaltyRecipientBalance - beforeRoyaltyRecipientBalance) == 0.05 ether); - // 100 bps finders fee (Remaining 0.95 ETH * finders fee = 0.0095 ETH) - require((afterFinderBalance - beforeFinderBalance) == 0.0095 ether); - // 200 bps listing fee (Remaining 0.95 ETH * listing fee = 0.019 ETH) - require((afterListingFeeRecipientBalance - beforeListingFeeRecipientBalance) == 0.019 ether); - // Remaining 0.855 ETH paid to seller - require((afterSellerBalance - beforeSellerBalance) == 0.9215 ether); - // NFT transferred to buyer - require((beforeTokenOwner == address(seller)) && afterTokenOwner == address(buyer)); - } - - // /// ------------ ERC-20 Offer ------------ /// - - function runERC20() public { - vm.prank(address(buyer)); - uint256 id = offers.createOffer(address(token), 0, address(weth), 1 ether, 0, 100, 200, address(listingFeeRecipient)); - - vm.prank(address(seller)); - offers.fillOffer(address(token), 0, id, 1 ether, address(weth), address(finder)); - } - - function test_ERC20Integration() public { - uint256 beforeSellerBalance = weth.balanceOf(address(seller)); - uint256 beforeBuyerBalance = weth.balanceOf(address(buyer)); - uint256 beforeRoyaltyRecipientBalance = weth.balanceOf(address(royaltyRecipient)); - uint256 beforeFinderBalance = weth.balanceOf(address(finder)); - uint256 beforeListingFeeRecipientBalance = weth.balanceOf(address(listingFeeRecipient)); - address beforeTokenOwner = token.ownerOf(0); - runERC20(); - uint256 afterSellerBalance = weth.balanceOf(address(seller)); - uint256 afterBuyerBalance = weth.balanceOf(address(buyer)); - uint256 afterRoyaltyRecipientBalance = weth.balanceOf(address(royaltyRecipient)); - uint256 afterFinderBalance = weth.balanceOf(address(finder)); - uint256 afterListingFeeRecipientBalance = weth.balanceOf(address(listingFeeRecipient)); - address afterTokenOwner = token.ownerOf(0); - - // 1 WETH withdrawn from seller - assertEq((beforeBuyerBalance - afterBuyerBalance), 1 ether); - // 0.05 WETH creator royalty - assertEq((afterRoyaltyRecipientBalance - beforeRoyaltyRecipientBalance), 0.05 ether); - // 0.095 WETH finders fee (0.95 WETH * 10% finders fee) - assertEq((afterFinderBalance - beforeFinderBalance), 0.0095 ether); - assertEq((afterListingFeeRecipientBalance - beforeListingFeeRecipientBalance), 0.019 ether); - - // Remaining 0.9215 WETH paid to buyer - assertEq((afterSellerBalance - beforeSellerBalance), 0.9215 ether); - // NFT transferred to seller - require((beforeTokenOwner == address(seller)) && afterTokenOwner == address(buyer)); - } -} diff --git a/contracts/test/modules/Offers/Omnibus/OffersOmnibus.t.sol b/contracts/test/modules/Offers/Omnibus/OffersOmnibus.t.sol deleted file mode 100644 index b1c5d3ca..00000000 --- a/contracts/test/modules/Offers/Omnibus/OffersOmnibus.t.sol +++ /dev/null @@ -1,377 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {OffersOmnibus} from "../../../../modules/Offers/Omnibus/OffersOmnibus.sol"; -import {OffersDataStorage} from "../../../../modules/Offers/Omnibus/OffersDataStorage.sol"; -import {Zorb} from "../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../utils/modules/RoyaltyEngine.sol"; - -import {TestERC721} from "../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../utils/tokens/WETH.sol"; -import {VM} from "../../../utils/VM.sol"; - -/// @title OffersOmnibusTest -/// @notice Unit Tests for Offers Omnibus -contract OffersOmnibusTest is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - OffersOmnibus internal offers; - TestERC721 internal token; - WETH internal weth; - - Zorb internal maker; - Zorb internal taker; - Zorb internal finder; - Zorb internal royaltyRecipient; - Zorb internal listingFeeRecipient; - - function setUp() public { - // Cheatcodes - vm = VM(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - maker = new Zorb(address(ZMM)); - taker = new Zorb(address(ZMM)); - finder = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - listingFeeRecipient = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - token = new TestERC721(); - weth = new WETH(); - - // Deploy Offers v1.0 - offers = new OffersOmnibus(address(erc20TransferHelper), address(erc721TransferHelper), address(royaltyEngine), address(ZPFS), address(weth)); - registrar.registerModule(address(offers)); - - // Set maker balance - vm.deal(address(maker), 100 ether); - - // Mint taker token - token.mint(address(taker), 0); - - // Maker swap 50 ETH <> 50 WETH - vm.prank(address(maker)); - weth.deposit{value: 50 ether}(); - - // Users approve Offers module - maker.setApprovalForModule(address(offers), true); - taker.setApprovalForModule(address(offers), true); - - // Maker approve ERC20TransferHelper - vm.prank(address(maker)); - weth.approve(address(erc20TransferHelper), 50 ether); - - // Taker approve ERC721TransferHelper - vm.prank(address(taker)); - token.setApprovalForAll(address(erc721TransferHelper), true); - } - - /// ------------ CREATE NFT OFFER ------------ /// - - function testGas_CreateOffer() public { - vm.prank(address(maker)); - offers.createOffer(address(token), 0, address(weth), 1 ether, uint96(block.timestamp + 100000), 100, 200, address(listingFeeRecipient)); - } - - function testGas_CreateOfferMinimal() public { - vm.prank(address(maker)); - offers.createOfferMinimal{value: 1 ether}(address(token), 0); - } - - function test_CreateETHOffer() public { - uint256 makerBalanceBefore = address(maker).balance; - uint256 makerWethBalanceBefore = weth.balanceOf(address(maker)); - vm.prank(address(maker)); - offers.createOffer{value: 1 ether}(address(token), 0, address(0), 1 ether, 0, 100, 200, address(listingFeeRecipient)); - uint256 makerBalanceAfter = address(maker).balance; - uint256 makerWethBalanceAfter = weth.balanceOf(address(maker)); - assertEq(makerBalanceBefore - makerBalanceAfter, 1 ether); - assertEq(makerWethBalanceAfter - makerWethBalanceBefore, 1 ether); - OffersDataStorage.FullOffer memory offer = offers.getFullOffer(address(token), 0, 1); - assertEq(offer.amount, 1 ether); - assertEq(offer.maker, address(maker)); - assertEq(offer.expiry, 0); - assertEq(offer.findersFeeBps, 100); - assertEq(offer.currency, address(0)); - assertEq(offer.listingFeeRecipient, address(listingFeeRecipient)); - assertEq(offer.listingFeeBps, 200); - } - - function test_CreateERC20Offer() public { - vm.prank(address(maker)); - offers.createOffer(address(token), 0, address(weth), 1 ether, 0, 100, 200, address(listingFeeRecipient)); - OffersDataStorage.FullOffer memory offer = offers.getFullOffer(address(token), 0, 1); - assertEq(offer.amount, 1 ether); - assertEq(offer.maker, address(maker)); - assertEq(offer.expiry, 0); - assertEq(offer.findersFeeBps, 100); - assertEq(offer.currency, address(weth)); - assertEq(offer.listingFeeRecipient, address(listingFeeRecipient)); - assertEq(offer.listingFeeBps, 200); - } - - function test_CreateOfferMinimal() public { - vm.prank(address(maker)); - offers.createOfferMinimal{value: 1 ether}(address(token), 0); - OffersDataStorage.FullOffer memory offer = offers.getFullOffer(address(token), 0, 1); - assertEq(offer.amount, 1 ether); - assertEq(offer.maker, address(maker)); - assertEq(offer.expiry, 0); - assertEq(offer.findersFeeBps, 0); - assertEq(offer.currency, address(0)); - assertEq(offer.listingFeeRecipient, address(0)); - assertEq(offer.listingFeeBps, 0); - } - - function test_CreateOfferWithExpiry() public { - uint256 makerBalanceBefore = address(maker).balance; - uint256 makerWethBalanceBefore = weth.balanceOf(address(maker)); - vm.prank(address(maker)); - uint96 start = uint96(block.timestamp); - uint96 tomorrow = start + 1 days; - offers.createOffer{value: 1 ether}(address(token), 0, address(0), 1 ether, tomorrow, 100, 200, address(listingFeeRecipient)); - vm.warp(tomorrow + 1 days); - vm.startPrank(address(taker)); - vm.expectRevert(abi.encodeWithSignature("OFFER_EXPIRED()")); - offers.fillOffer(address(token), 0, 1, 1 ether, address(0), address(0)); - vm.warp(start + 1 hours); - offers.fillOffer(address(token), 0, 1, 1 ether, address(0), address(0)); - } - - function testFail_CannotCreateOfferWithoutAttachingFunds() public { - vm.prank(address(maker)); - offers.createOffer(address(token), 0, address(0), 1 ether, 0, 0, 0, address(0)); - } - - function testFail_CannotCreateOfferWithInvalidFindersFeeBps() public { - vm.prank(address(maker)); - offers.createOffer(address(token), 0, address(weth), 1 ether, 0, 10001, 0, address(0)); - } - - function testFail_CannotCreateOfferWithInvalidFindersAndListingFeeBps() public { - vm.prank(address(maker)); - offers.createOffer(address(token), 0, address(weth), 1 ether, 0, 5000, 5001, address(listingFeeRecipient)); - } - - function testFail_CannotCreateOfferWithInvalidExpiry() public { - vm.prank(address(maker)); - vm.warp(1000); - offers.createOffer(address(token), 0, address(weth), 1 ether, 500, 100, 200, address(listingFeeRecipient)); - } - - function testFail_CannotCreateERC20OfferWithMsgValue() public { - vm.prank(address(maker)); - offers.createOffer{value: 1 ether}(address(token), 0, address(weth), 1 ether, 0, 100, 200, address(listingFeeRecipient)); - } - - function testFail_CannotCreateERC20OfferInsufficientBalance() public { - vm.prank(address(maker)); - offers.createOffer(address(token), 0, address(weth), 1000 ether, 0, 100, 200, address(listingFeeRecipient)); - } - - function testFail_CannotCreateETHOfferInsufficientWethAllowance() public { - vm.startPrank(address(maker)); - weth.approve(address(erc20TransferHelper), 0); - offers.createOffer{value: 1 ether}(address(token), 0, address(0), 1 ether, 0, 100, 200, address(listingFeeRecipient)); - vm.stopPrank(); - } - - function testFail_CannotCreateERC20OfferInsufficientAllowance() public { - vm.startPrank(address(maker)); - weth.approve(address(erc20TransferHelper), 0); - offers.createOffer(address(token), 0, address(weth), 1 ether, 0, 100, 200, address(listingFeeRecipient)); - vm.stopPrank(); - } - - /// ------------ SET NFT OFFER ------------ /// - - function test_IncreaseETHOffer() public { - uint256 wethBalanceBefore = weth.balanceOf(address(maker)); - vm.startPrank(address(maker)); - offers.createOfferMinimal{value: 1 ether}(address(token), 0); - uint256 wethBalanceAfterCreate = weth.balanceOf(address(maker)); - vm.warp(1 hours); - offers.setOfferAmount{value: 1 ether}(address(token), 0, 1, address(0), 2 ether); - vm.stopPrank(); - uint256 wethBalanceAfterUpdate = weth.balanceOf(address(maker)); - OffersDataStorage.FullOffer memory offer = offers.getFullOffer(address(token), 0, 1); - assertEq(offer.amount, 2 ether); - assertEq(wethBalanceAfterCreate - wethBalanceBefore, 1 ether); - assertEq(wethBalanceAfterUpdate - wethBalanceBefore, 2 ether); - } - - function test_DecreaseETHOffer() public { - uint256 wethBalanceBefore = weth.balanceOf(address(maker)); - vm.startPrank(address(maker)); - offers.createOfferMinimal{value: 2 ether}(address(token), 0); - uint256 wethBalanceAfterCreate = weth.balanceOf(address(maker)); - vm.warp(1 hours); - offers.setOfferAmount(address(token), 0, 1, address(0), 1 ether); - vm.stopPrank(); - uint256 wethBalanceAfterUpdate = weth.balanceOf(address(maker)); - OffersDataStorage.FullOffer memory offer = offers.getFullOffer(address(token), 0, 1); - assertEq(offer.amount, 1 ether); - assertEq(wethBalanceAfterCreate - wethBalanceBefore, 2 ether); - assertEq(wethBalanceAfterCreate, wethBalanceAfterUpdate); - } - - function test_IncreaseETHOfferWithERC20() public { - vm.startPrank(address(maker)); - offers.createOfferMinimal{value: 1 ether}(address(token), 0); - vm.warp(1 hours); - offers.setOfferAmount(address(token), 0, 1, address(weth), 2 ether); - vm.stopPrank(); - OffersDataStorage.FullOffer memory offer = offers.getFullOffer(address(token), 0, 1); - assertEq(offer.amount, 2 ether); - assertEq(offer.currency, address(weth)); - assertEq(address(offers).balance, 0 ether); - } - - function test_DecreaseETHOfferWithERC20() public { - vm.startPrank(address(maker)); - offers.createOfferMinimal{value: 1 ether}(address(token), 0); - vm.warp(1 hours); - offers.setOfferAmount(address(token), 0, 1, address(weth), 0.5 ether); - vm.stopPrank(); - OffersDataStorage.FullOffer memory offer = offers.getFullOffer(address(token), 0, 1); - assertEq(offer.amount, 0.5 ether); - assertEq(offer.currency, address(weth)); - assertEq(address(offers).balance, 0 ether); - } - - function testRevert_OnlySellerCanUpdateOffer() public { - vm.prank(address(maker)); - offers.createOfferMinimal{value: 1 ether}(address(token), 0); - vm.expectRevert(abi.encodeWithSignature("CALLER_NOT_MAKER()")); - offers.setOfferAmount(address(token), 0, 1, address(0), 0.5 ether); - } - - function testRevert_CannotIncreaseEthOfferWithoutAttachingNecessaryFunds() public { - vm.startPrank(address(maker)); - offers.createOfferMinimal{value: 0.1 ether}(address(token), 0); - vm.expectRevert(abi.encodeWithSignature("INSUFFICIENT_BALANCE()")); - offers.setOfferAmount(address(token), 0, 1, address(0), 51 ether); - vm.stopPrank(); - } - - function testRevert_CannotUpdateOfferWithPreviousAmount() public { - vm.startPrank(address(maker)); - offers.createOfferMinimal{value: 1 ether}(address(token), 0); - vm.warp(1 hours); - vm.expectRevert(abi.encodeWithSignature("SAME_OFFER()")); - offers.setOfferAmount{value: 1 ether}(address(token), 0, 1, address(0), 1 ether); - vm.stopPrank(); - } - - function testRevert_CannotUpdateInactiveOffer() public { - vm.prank(address(maker)); - offers.createOfferMinimal{value: 1 ether}(address(token), 0); - vm.prank(address(taker)); - offers.fillOffer(address(token), 0, 1, 1 ether, address(0), address(finder)); - vm.prank(address(maker)); - vm.expectRevert(abi.encodeWithSignature("CALLER_NOT_MAKER()")); - offers.setOfferAmount(address(token), 0, 1, address(0), 0.5 ether); - } - - /// ------------ CANCEL NFT OFFER ------------ /// - - function test_CancelNFTOffer() public { - vm.startPrank(address(maker)); - offers.createOfferMinimal{value: 1 ether}(address(token), 0); - (uint256 beforeAmount, , ) = offers.offers(address(token), 0, 1); - require(beforeAmount == 1 ether); - offers.cancelOffer(address(token), 0, 1); - (uint256 afterAmount, , ) = offers.offers(address(token), 0, 1); - require(afterAmount == 0); - vm.stopPrank(); - } - - function testRevert_CannotCancelInactiveOffer() public { - vm.prank(address(maker)); - offers.createOfferMinimal{value: 1 ether}(address(token), 0); - vm.prank(address(taker)); - offers.fillOffer(address(token), 0, 1, 1 ether, address(0), address(finder)); - vm.prank(address(maker)); - vm.expectRevert(abi.encodeWithSignature("CALLER_NOT_MAKER()")); - offers.cancelOffer(address(token), 0, 1); - } - - function testRevert_OnlySellerCanCancelOffer() public { - vm.prank(address(maker)); - offers.createOfferMinimal{value: 1 ether}(address(token), 0); - vm.expectRevert(abi.encodeWithSignature("CALLER_NOT_MAKER()")); - offers.cancelOffer(address(token), 0, 1); - } - - // /// ------------ FILL NFT OFFER ------------ /// - - function test_FillNFTOffer() public { - vm.prank(address(maker)); - offers.createOfferMinimal{value: 1 ether}(address(token), 0); - address beforeTokenOwner = token.ownerOf(0); - vm.prank(address(taker)); - offers.fillOffer(address(token), 0, 1, 1 ether, address(0), address(finder)); - address afterTokenOwner = token.ownerOf(0); - require(beforeTokenOwner == address(taker) && afterTokenOwner == address(maker)); - } - - function testRevert_OnlyTokenHolderCanFillOffer() public { - vm.prank(address(maker)); - uint256 id = offers.createOfferMinimal{value: 1 ether}(address(token), 0); - vm.expectRevert(abi.encodeWithSignature("NOT_TOKEN_OWNER()")); - offers.fillOffer(address(token), 0, id, 1 ether, address(0), address(finder)); - } - - function testRevert_CannotFillInactiveOffer() public { - vm.prank(address(maker)); - uint256 id = offers.createOfferMinimal{value: 1 ether}(address(token), 0); - vm.prank(address(taker)); - offers.fillOffer(address(token), 0, id, 1 ether, address(0), address(finder)); - vm.prank(address(taker)); - vm.expectRevert(abi.encodeWithSignature("INACTIVE_OFFER()")); - offers.fillOffer(address(token), 0, id, 1 ether, address(0), address(finder)); - } - - function testRevert_AcceptCurrencyMustMatchOffer() public { - vm.prank(address(maker)); - uint256 id = offers.createOfferMinimal{value: 1 ether}(address(token), 0); - vm.prank(address(taker)); - vm.expectRevert(abi.encodeWithSignature("INCORRECT_CURRENCY_OR_AMOUNT()")); - offers.fillOffer(address(token), 0, id, 1 ether, address(weth), address(finder)); - } - - function testRevert_AcceptAmountMustMatchOffer() public { - vm.prank(address(maker)); - uint256 id = offers.createOfferMinimal{value: 1 ether}(address(token), 0); - vm.prank(address(taker)); - vm.expectRevert(abi.encodeWithSignature("INCORRECT_CURRENCY_OR_AMOUNT()")); - offers.fillOffer(address(token), 0, id, 0.5 ether, address(0), address(finder)); - } -} diff --git a/contracts/test/modules/ReserveAuction/Core/ERC20/ReserveAuctionCoreErc20.t.integration.sol b/contracts/test/modules/ReserveAuction/Core/ERC20/ReserveAuctionCoreErc20.t.integration.sol deleted file mode 100644 index e0de9087..00000000 --- a/contracts/test/modules/ReserveAuction/Core/ERC20/ReserveAuctionCoreErc20.t.integration.sol +++ /dev/null @@ -1,169 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {ReserveAuctionCoreErc20} from "../../../../../modules/ReserveAuction/Core/ERC20/ReserveAuctionCoreErc20.sol"; -import {Zorb} from "../../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../../utils/modules/RoyaltyEngine.sol"; -import {TestERC721} from "../../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../../utils/tokens/WETH.sol"; -import {VM} from "../../../../utils/VM.sol"; - -/// @title ReserveAuctionCoreErc20IntegrationTest -/// @notice Integration Tests for Reserve Auction Core ERC-20 -contract ReserveAuctionCoreErc20IntegrationTest is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - ReserveAuctionCoreErc20 internal auctions; - TestERC721 internal token; - WETH internal weth; - - Zorb internal seller; - Zorb internal sellerFundsRecipient; - Zorb internal operator; - Zorb internal royaltyRecipient; - Zorb internal bidder; - Zorb internal otherBidder; - Zorb internal protocolFeeRecipient; - - function setUp() public { - // Cheatcodes - vm = VM(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - seller = new Zorb(address(ZMM)); - sellerFundsRecipient = new Zorb(address(ZMM)); - operator = new Zorb(address(ZMM)); - bidder = new Zorb(address(ZMM)); - otherBidder = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - protocolFeeRecipient = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - token = new TestERC721(); - weth = new WETH(); - - // Deploy Reserve Auction Core ERC-20 - auctions = new ReserveAuctionCoreErc20( - address(erc20TransferHelper), - address(erc721TransferHelper), - address(royaltyEngine), - address(ZPFS), - address(weth) - ); - registrar.registerModule(address(auctions)); - - // Set module fee - vm.prank(address(registrar)); - ZPFS.setFeeParams(address(auctions), address(protocolFeeRecipient), 1); - - // Set balances - vm.deal(address(seller), 100 ether); - vm.deal(address(bidder), 100 ether); - vm.deal(address(otherBidder), 100 ether); - - // Mint seller token - token.mint(address(seller), 0); - - // Bidder swap 50 ETH <> 50 WETH - vm.prank(address(bidder)); - weth.deposit{value: 50 ether}(); - - // otherBidder swap 50 ETH <> 50 WETH - vm.prank(address(otherBidder)); - weth.deposit{value: 50 ether}(); - - // Users approve module - seller.setApprovalForModule(address(auctions), true); - bidder.setApprovalForModule(address(auctions), true); - otherBidder.setApprovalForModule(address(auctions), true); - - // Seller approve ERC721TransferHelper - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - - // Bidder approve ERC20TransferHelper - vm.prank(address(bidder)); - weth.approve(address(erc20TransferHelper), 50 ether); - - // otherBidder approve ERC20TransferHelper - vm.prank(address(otherBidder)); - weth.approve(address(erc20TransferHelper), 50 ether); - } - - function runERC20() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 0.1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 0.1 ether); - - vm.warp(10 hours); - vm.prank(address(otherBidder)); - auctions.createBid(address(token), 0, 0.5 ether); - - vm.warp(1 days); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether); - - vm.warp(1 days + 1 hours); - auctions.settleAuction(address(token), 0); - } - - function test_ERC20Integration() public { - uint256 beforeSellerBalance = weth.balanceOf(address(sellerFundsRecipient)); - uint256 beforeBidderBalance = weth.balanceOf(address(bidder)); - uint256 beforeOtherBidderBalance = weth.balanceOf(address(otherBidder)); - uint256 beforeRoyaltyRecipientBalance = weth.balanceOf(address(royaltyRecipient)); - uint256 beforeProtocolFeeRecipient = weth.balanceOf(address(protocolFeeRecipient)); - address beforeTokenOwner = token.ownerOf(0); - - runERC20(); - - uint256 afterSellerBalance = weth.balanceOf(address(sellerFundsRecipient)); - uint256 afterBidderBalance = weth.balanceOf(address(bidder)); - uint256 afterOtherBidderBalance = weth.balanceOf(address(otherBidder)); - uint256 afterRoyaltyRecipientBalance = weth.balanceOf(address(royaltyRecipient)); - uint256 afterProtocolFeeRecipient = weth.balanceOf(address(protocolFeeRecipient)); - address afterTokenOwner = token.ownerOf(0); - - // 1 ETH withdrawn from winning bidder - require((beforeBidderBalance - afterBidderBalance) == 1 ether); - // Losing bidder refunded - require(beforeOtherBidderBalance == afterOtherBidderBalance); - // 0.05 ETH creator royalty - require((afterRoyaltyRecipientBalance - beforeRoyaltyRecipientBalance) == 0.05 ether); - // 1 bps protocol fee (Remaining 0.95 ETH * 0.01% protocol fee = 0.000095 ETH) - require((afterProtocolFeeRecipient - beforeProtocolFeeRecipient) == 0.000095 ether); - // Remaining 0.949905 ETH paid to seller - require((afterSellerBalance - beforeSellerBalance) == 0.949905 ether); - // NFT transferred to winning bidder - require(beforeTokenOwner == address(seller) && afterTokenOwner == address(bidder)); - } -} diff --git a/contracts/test/modules/ReserveAuction/Core/ERC20/ReserveAuctionCoreErc20.t.sol b/contracts/test/modules/ReserveAuction/Core/ERC20/ReserveAuctionCoreErc20.t.sol deleted file mode 100644 index 6b67e0ac..00000000 --- a/contracts/test/modules/ReserveAuction/Core/ERC20/ReserveAuctionCoreErc20.t.sol +++ /dev/null @@ -1,478 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {ReserveAuctionCoreErc20} from "../../../../../modules/ReserveAuction/Core/ERC20/ReserveAuctionCoreErc20.sol"; -import {Zorb} from "../../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../../utils/modules/RoyaltyEngine.sol"; -import {TestERC20} from "../../../../utils/tokens/TestERC20.sol"; -import {TestERC721} from "../../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../../utils/tokens/WETH.sol"; -import {VM} from "../../../../utils/VM.sol"; - -/// @title ReserveAuctionCoreErc20Test -/// @notice Unit Tests for Reserve Auction Core ERC-20 -contract ReserveAuctionCoreErc20Test is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - ReserveAuctionCoreErc20 internal auctions; - TestERC20 internal erc20; - TestERC721 internal token; - WETH internal weth; - - Zorb internal seller; - Zorb internal sellerFundsRecipient; - Zorb internal operator; - Zorb internal royaltyRecipient; - Zorb internal bidder; - Zorb internal otherBidder; - - function setUp() public { - // Cheatcodes - vm = VM(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - seller = new Zorb(address(ZMM)); - sellerFundsRecipient = new Zorb(address(ZMM)); - operator = new Zorb(address(ZMM)); - bidder = new Zorb(address(ZMM)); - otherBidder = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - erc20 = new TestERC20(); - token = new TestERC721(); - weth = new WETH(); - - // Deploy Reserve Auction Core ERC-20 - auctions = new ReserveAuctionCoreErc20( - address(erc20TransferHelper), - address(erc721TransferHelper), - address(royaltyEngine), - address(ZPFS), - address(weth) - ); - registrar.registerModule(address(auctions)); - - // Set balances - vm.deal(address(seller), 100 ether); - vm.deal(address(bidder), 100 ether); - vm.deal(address(otherBidder), 100 ether); - - // Mint seller token - token.mint(address(seller), 0); - - // Mint bidder 2^96 ERC-20 tokens - erc20.mint(address(bidder), 2**96); - - // Bidder swap 50 ETH <> 50 WETH - vm.prank(address(bidder)); - weth.deposit{value: 50 ether}(); - - // otherBidder swap 50 ETH <> 50 WETH - vm.prank(address(otherBidder)); - weth.deposit{value: 50 ether}(); - - // Users approve module - seller.setApprovalForModule(address(auctions), true); - bidder.setApprovalForModule(address(auctions), true); - otherBidder.setApprovalForModule(address(auctions), true); - - // Seller approve ERC721TransferHelper - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - - // Bidder approve ERC20TransferHelper for TestERC20 - vm.prank(address(bidder)); - erc20.approve(address(erc20TransferHelper), 2**96); - - // Bidder approve ERC20TransferHelper for WETH - vm.prank(address(bidder)); - weth.approve(address(erc20TransferHelper), 50 ether); - - // otherBidder approve ERC20TransferHelper - vm.prank(address(otherBidder)); - weth.approve(address(erc20TransferHelper), 50 ether); - } - - /// /// - /// CREATE AUCTION /// - /// /// - - function testGas_CreateERC20Auction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - } - - function test_CreateInstantERC20Auction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - ( - address creator, - address fundsRecipient, - uint256 reservePrice, - uint256 highestBid, - address highestBidder, - uint256 duration, - uint256 startTime, - address currency, - uint256 firstBidTime - ) = auctions.auctionForNFT(address(token), 0); - - require(creator == address(seller)); - require(currency == address(weth)); - require(fundsRecipient == address(sellerFundsRecipient)); - require(highestBidder == address(0)); - require(highestBid == 0); - require(duration == 1 days); - require(startTime == 0); - require(firstBidTime == 0); - require(reservePrice == 1 ether); - } - - function test_CreateFutureERC20Auction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 1 days, address(weth)); - (, , , , , , uint256 startTime, , ) = auctions.auctionForNFT(address(token), 0); - - require(startTime == 1 days); - } - - function test_CreateERC20AuctionAndCancelPrevious() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.prank(address(seller)); - token.transferFrom(address(seller), address(sellerFundsRecipient), 0); - - sellerFundsRecipient.setApprovalForModule(address(auctions), true); - vm.startPrank(address(sellerFundsRecipient)); - token.setApprovalForAll(address(erc721TransferHelper), true); - auctions.createAuction(address(token), 0, 5 days, 12 ether, address(sellerFundsRecipient), 0, address(weth)); - vm.stopPrank(); - - (address creator, , uint256 reservePrice, , , uint256 duration, , , ) = auctions.auctionForNFT(address(token), 0); - - require(creator == address(sellerFundsRecipient)); - require(duration == 5 days); - require(reservePrice == 12 ether); - } - - function testRevert_MustBeTokenOwnerOrOperator() public { - vm.expectRevert("ONLY_TOKEN_OWNER_OR_OPERATOR"); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - } - - function testRevert_MustSpecifySellerFundsRecipient() public { - vm.prank(address(seller)); - vm.expectRevert("INVALID_FUNDS_RECIPIENT"); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(0), 0, address(weth)); - } - - /// /// - /// UPDATE RESERVE PRICE /// - /// /// - - function test_SetReservePrice() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.prank(address(seller)); - auctions.setAuctionReservePrice(address(token), 0, 5 ether); - - (, , uint256 reservePrice, , , , , , ) = auctions.auctionForNFT(address(token), 0); - - require(reservePrice == 5 ether); - } - - function testRevert_UpdateMustBeSeller() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.expectRevert("ONLY_SELLER"); - auctions.setAuctionReservePrice(address(token), 0, 5 ether); - } - - function testRevert_CannotUpdateAuctionDoesNotExist() public { - vm.expectRevert("ONLY_SELLER"); - auctions.setAuctionReservePrice(address(token), 0, 5 ether); - } - - function testRevert_CannotUpdateActiveAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether); - - vm.warp(1 hours + 1 minutes); - vm.prank(address(seller)); - vm.expectRevert("AUCTION_STARTED"); - auctions.setAuctionReservePrice(address(token), 0, 20 ether); - } - - /// /// - /// CANCEL AUCTION /// - /// /// - - function test_CancelAuction() public { - vm.startPrank(address(seller)); - - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - auctions.cancelAuction(address(token), 0); - - vm.stopPrank(); - - (address creator, , , , , , , , ) = auctions.auctionForNFT(address(token), 0); - require(creator == address(0)); - } - - function testRevert_OnlySellerCanCancel() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.expectRevert("ONLY_SELLER_OR_TOKEN_OWNER"); - auctions.cancelAuction(address(token), 0); - } - - function testRevert_CannotCancelActiveAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether); - - vm.prank(address(seller)); - vm.expectRevert("AUCTION_STARTED"); - auctions.cancelAuction(address(token), 0); - } - - /// /// - /// CREATE BID /// - /// /// - - function test_CreateFirstBid() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether); - } - - function test_StoreTimeOfFirstBid() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether); - - (, , , , , , , , uint256 firstBidTime) = auctions.auctionForNFT(address(token), 0); - - require(firstBidTime == 1 hours); - } - - function test_RefundPreviousBidder() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether); - - uint256 beforeBalance = weth.balanceOf(address(bidder)); - - vm.prank(address(otherBidder)); - auctions.createBid(address(token), 0, 2 ether); - - uint256 afterBalance = weth.balanceOf(address(bidder)); - require(afterBalance - beforeBalance == 1 ether); - } - - function test_TransferNFTIntoEscrow() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether); - - require(token.ownerOf(0) == address(auctions)); - } - - function test_ExtendAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.warp(5 minutes); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether); - - vm.warp(55 minutes); - vm.prank(address(otherBidder)); - auctions.createBid(address(token), 0, 2 ether); - - (, , , , , uint256 newDuration, , , ) = auctions.auctionForNFT(address(token), 0); - - require(newDuration == 1 hours + 5 minutes); - } - - function testRevert_MustApproveModule() public { - seller.setApprovalForModule(address(auctions), false); - - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.prank(address(bidder)); - vm.expectRevert("module has not been approved by user"); - auctions.createBid(address(token), 0, 1 ether); - } - - function testRevert_SellerMustApproveERC721TransferHelper() public { - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), false); - - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.prank(address(bidder)); - vm.expectRevert("ERC721: transfer caller is not owner nor approved"); - auctions.createBid(address(token), 0, 1 ether); - } - - function testRevert_InvalidTransferBeforeFirstBid() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.prank(address(seller)); - token.transferFrom(address(seller), address(otherBidder), 0); - - vm.prank(address(bidder)); - vm.expectRevert("ERC721: transfer caller is not owner nor approved"); - auctions.createBid(address(token), 0, 1 ether); - } - - function testRevert_CannotBidOnExpiredAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 5 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.warp(1 days); - - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether); - - vm.warp(6 days); - - vm.prank(address(otherBidder)); - vm.expectRevert("AUCTION_OVER"); - auctions.createBid(address(token), 0, 2 ether); - } - - function testRevert_CannotBidOnAuctionNotStarted() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 1 days, address(weth)); - - vm.prank(address(bidder)); - vm.expectRevert("AUCTION_NOT_STARTED"); - auctions.createBid(address(token), 0, 2 ether); - } - - function testRevert_CannotBidOnAuctionNotActive() public { - vm.expectRevert("AUCTION_DOES_NOT_EXIST"); - auctions.createBid(address(token), 0, 2 ether); - } - - function testRevert_BidMustMeetReservePrice() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.prank(address(bidder)); - vm.expectRevert("RESERVE_PRICE_NOT_MET"); - auctions.createBid(address(token), 0, 0.5 ether); - } - - function testRevert_BidMustBe10PercentGreaterThanPrevious() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether); - - vm.warp(1 hours + 1 minutes); - vm.prank(address(otherBidder)); - vm.expectRevert("MINIMUM_BID_NOT_MET"); - auctions.createBid(address(token), 0, 1.01 ether); - } - - /// /// - /// SETTLE AUCTION /// - /// /// - - function test_SettleAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether); - - vm.warp(10 hours); - vm.prank(address(otherBidder)); - auctions.createBid(address(token), 0, 5 ether); - - vm.warp(1 days + 1 hours); - auctions.settleAuction(address(token), 0); - - require(token.ownerOf(0) == address(otherBidder)); - } - - function testRevert_AuctionNotStarted() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.expectRevert("AUCTION_NOT_STARTED"); - auctions.settleAuction(address(token), 0); - } - - function testRevert_AuctionNotOver() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth)); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether); - - vm.expectRevert("AUCTION_NOT_OVER"); - auctions.settleAuction(address(token), 0); - } -} diff --git a/contracts/test/modules/ReserveAuction/Core/ETH/ReserveAuctionCoreEth.integration.t.sol b/contracts/test/modules/ReserveAuction/Core/ETH/ReserveAuctionCoreEth.integration.t.sol deleted file mode 100644 index 23dc6144..00000000 --- a/contracts/test/modules/ReserveAuction/Core/ETH/ReserveAuctionCoreEth.integration.t.sol +++ /dev/null @@ -1,162 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {ReserveAuctionCoreEth} from "../../../../../modules/ReserveAuction/Core/ETH/ReserveAuctionCoreEth.sol"; -import {Zorb} from "../../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../../utils/modules/RoyaltyEngine.sol"; -import {TestERC721} from "../../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../../utils/tokens/WETH.sol"; -import {VM} from "../../../../utils/VM.sol"; - -/// @title ReserveAuctionCoreEthIntegrationTest -/// @notice Integration Tests for Reserve Auction Core ETH -contract ReserveAuctionCoreEthIntegrationTest is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - ReserveAuctionCoreEth internal auctions; - TestERC721 internal token; - WETH internal weth; - - Zorb internal seller; - Zorb internal sellerFundsRecipient; - Zorb internal finder; - Zorb internal royaltyRecipient; - Zorb internal bidder; - Zorb internal otherBidder; - Zorb internal protocolFeeRecipient; - - function setUp() public { - // Cheatcodes - vm = VM(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - seller = new Zorb(address(ZMM)); - sellerFundsRecipient = new Zorb(address(ZMM)); - bidder = new Zorb(address(ZMM)); - otherBidder = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - protocolFeeRecipient = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - token = new TestERC721(); - weth = new WETH(); - - // Deploy Reserve Auction Core ETH - auctions = new ReserveAuctionCoreEth(address(erc721TransferHelper), address(royaltyEngine), address(ZPFS), address(weth)); - registrar.registerModule(address(auctions)); - - // Set module fee - vm.prank(address(registrar)); - ZPFS.setFeeParams(address(auctions), address(protocolFeeRecipient), 1); - - // Set balances - vm.deal(address(seller), 100 ether); - vm.deal(address(bidder), 100 ether); - vm.deal(address(otherBidder), 100 ether); - - // Mint seller token - token.mint(address(seller), 0); - - // Bidder swap 50 ETH <> 50 WETH - vm.prank(address(bidder)); - weth.deposit{value: 50 ether}(); - - // otherBidder swap 50 ETH <> 50 WETH - vm.prank(address(otherBidder)); - weth.deposit{value: 50 ether}(); - - // Users approve ReserveAuction module - seller.setApprovalForModule(address(auctions), true); - bidder.setApprovalForModule(address(auctions), true); - otherBidder.setApprovalForModule(address(auctions), true); - - // Seller approve ERC721TransferHelper - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - - // Bidder approve ERC20TransferHelper - vm.prank(address(bidder)); - weth.approve(address(erc20TransferHelper), 50 ether); - - // otherBidder approve ERC20TransferHelper - vm.prank(address(otherBidder)); - weth.approve(address(erc20TransferHelper), 50 ether); - } - - function runETH() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 0.1 ether, address(sellerFundsRecipient), 0); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid{value: 0.1 ether}(address(token), 0); - - vm.warp(10 hours); - vm.prank(address(otherBidder)); - auctions.createBid{value: 0.5 ether}(address(token), 0); - - vm.warp(1 days); - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - - vm.warp(1 days + 1 hours); - auctions.settleAuction(address(token), 0); - } - - function test_ETHIntegration() public { - uint256 beforeSellerBalance = address(sellerFundsRecipient).balance; - uint256 beforeBidderBalance = address(bidder).balance; - uint256 beforeOtherBidderBalance = address(otherBidder).balance; - uint256 beforeRoyaltyRecipientBalance = address(royaltyRecipient).balance; - uint256 beforeProtocolFeeRecipient = address(protocolFeeRecipient).balance; - address beforeTokenOwner = token.ownerOf(0); - - runETH(); - - uint256 afterSellerBalance = address(sellerFundsRecipient).balance; - uint256 afterBidderBalance = address(bidder).balance; - uint256 afterOtherBidderBalance = address(otherBidder).balance; - uint256 afterRoyaltyRecipientBalance = address(royaltyRecipient).balance; - uint256 afterProtocolFeeRecipient = address(protocolFeeRecipient).balance; - address afterTokenOwner = token.ownerOf(0); - - // 1 ETH withdrawn from winning bidder - require((beforeBidderBalance - afterBidderBalance) == 1 ether); - // Losing bidder refunded - require(beforeOtherBidderBalance == afterOtherBidderBalance); - // 0.05 ETH creator royalty - require((afterRoyaltyRecipientBalance - beforeRoyaltyRecipientBalance) == 0.05 ether); - // 1 bps protocol fee (Remaining 0.95 ETH * 0.01% protocol fee = 0.000095 ETH) - require((afterProtocolFeeRecipient - beforeProtocolFeeRecipient) == 0.000095 ether); - // Remaining 0.949905 ETH paid to seller - require((afterSellerBalance - beforeSellerBalance) == 0.949905 ether); - // NFT transferred to winning bidder - require(beforeTokenOwner == address(seller) && afterTokenOwner == address(bidder)); - } -} diff --git a/contracts/test/modules/ReserveAuction/Core/ETH/ReserveAuctionCoreEth.t.sol b/contracts/test/modules/ReserveAuction/Core/ETH/ReserveAuctionCoreEth.t.sol deleted file mode 100644 index bca15364..00000000 --- a/contracts/test/modules/ReserveAuction/Core/ETH/ReserveAuctionCoreEth.t.sol +++ /dev/null @@ -1,442 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {ReserveAuctionCoreEth} from "../../../../../modules/ReserveAuction/Core/ETH/ReserveAuctionCoreEth.sol"; -import {Zorb} from "../../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../../utils/modules/RoyaltyEngine.sol"; -import {TestERC721} from "../../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../../utils/tokens/WETH.sol"; -import {VM} from "../../../../utils/VM.sol"; - -/// @title ReserveAuctionCoreEthTest -/// @notice Unit Tests for Reserve Auction Core ETH -contract ReserveAuctionCoreEthTest is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - ReserveAuctionCoreEth internal auctions; - TestERC721 internal token; - WETH internal weth; - - Zorb internal seller; - Zorb internal sellerFundsRecipient; - Zorb internal operator; - Zorb internal finder; - Zorb internal royaltyRecipient; - Zorb internal bidder; - Zorb internal otherBidder; - - function setUp() public { - // Cheatcodes - vm = VM(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - seller = new Zorb(address(ZMM)); - sellerFundsRecipient = new Zorb(address(ZMM)); - operator = new Zorb(address(ZMM)); - bidder = new Zorb(address(ZMM)); - otherBidder = new Zorb(address(ZMM)); - finder = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - token = new TestERC721(); - weth = new WETH(); - - // Deploy Reserve Auction Core ETH - auctions = new ReserveAuctionCoreEth(address(erc721TransferHelper), address(royaltyEngine), address(ZPFS), address(weth)); - registrar.registerModule(address(auctions)); - - // Set balances - vm.deal(address(seller), 100 ether); - vm.deal(address(bidder), 100 ether); - vm.deal(address(otherBidder), 100 ether); - - // Mint seller token - token.mint(address(seller), 0); - - // Users approve module - seller.setApprovalForModule(address(auctions), true); - bidder.setApprovalForModule(address(auctions), true); - otherBidder.setApprovalForModule(address(auctions), true); - - // Seller approve ERC721TransferHelper - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - } - - /// /// - /// CREATE AUCTION /// - /// /// - - function testGas_CreateAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0); - } - - function test_CreateInstantAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0); - - ( - address creator, - uint256 reservePrice, - address fundsRecipient, - uint256 highestBid, - address highestBidder, - uint256 duration, - uint256 startTime, - uint256 firstBidTime - ) = auctions.auctionForNFT(address(token), 0); - - require(creator == address(seller)); - require(fundsRecipient == address(sellerFundsRecipient)); - require(highestBidder == address(0)); - require(highestBid == 0); - require(duration == 1 days); - require(startTime == 0); - require(firstBidTime == 0); - require(reservePrice == 1 ether); - } - - function test_CreateFutureAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 1 days); - - (, , , , , , uint256 startTime, ) = auctions.auctionForNFT(address(token), 0); - require(startTime == 1 days); - } - - function test_CreateAuctionAndCancelPrevious() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0); - - vm.prank(address(seller)); - token.transferFrom(address(seller), address(sellerFundsRecipient), 0); - - sellerFundsRecipient.setApprovalForModule(address(auctions), true); - vm.startPrank(address(sellerFundsRecipient)); - token.setApprovalForAll(address(erc721TransferHelper), true); - auctions.createAuction(address(token), 0, 5 days, 12 ether, address(sellerFundsRecipient), 0); - vm.stopPrank(); - - (address creator, uint256 reservePrice, , , , uint256 duration, , ) = auctions.auctionForNFT(address(token), 0); - - require(creator == address(sellerFundsRecipient)); - require(duration == 5 days); - require(reservePrice == 12 ether); - } - - function testRevert_MustBeTokenOwnerOrOperator() public { - vm.expectRevert("ONLY_TOKEN_OWNER_OR_OPERATOR"); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0); - } - - function testRevert_MustSpecifySellerFundsRecipient() public { - vm.prank(address(seller)); - vm.expectRevert("INVALID_FUNDS_RECIPIENT"); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(0), 0); - } - - /// /// - /// UPDATE RESERVE PRICE /// - /// /// - - function test_SetReservePrice() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0); - - vm.prank(address(seller)); - auctions.setAuctionReservePrice(address(token), 0, 5 ether); - - (, uint256 reservePrice, , , , , , ) = auctions.auctionForNFT(address(token), 0); - - require(reservePrice == 5 ether); - } - - function testRevert_UpdateMustBeSeller() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0); - - vm.expectRevert("ONLY_SELLER"); - auctions.setAuctionReservePrice(address(token), 0, 5 ether); - } - - function testRevert_CannotUpdateActiveAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid{value: 5 ether}(address(token), 0); - - vm.warp(1 hours + 1 minutes); - vm.prank(address(seller)); - vm.expectRevert("AUCTION_STARTED"); - auctions.setAuctionReservePrice(address(token), 0, 20 ether); - } - - /// /// - /// CANCEL AUCTION /// - /// /// - - function test_CancelAuction() public { - vm.startPrank(address(seller)); - - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0); - auctions.cancelAuction(address(token), 0); - - vm.stopPrank(); - - (address creator, , , , , , , ) = auctions.auctionForNFT(address(token), 0); - require(creator == address(0)); - } - - function testRevert_OnlySellerCanCancel() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0); - - vm.expectRevert("ONLY_SELLER_OR_TOKEN_OWNER"); - auctions.cancelAuction(address(token), 0); - } - - function testRevert_CannotCancelActiveAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - - vm.prank(address(seller)); - vm.expectRevert("AUCTION_STARTED"); - auctions.cancelAuction(address(token), 0); - } - - /// /// - /// CREATE BID /// - /// /// - - function test_CreateFirstBid() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0); - - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - } - - function test_StoreTimeOfFirstBid() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - - (, , , , , , , uint32 firstBidTime) = auctions.auctionForNFT(address(token), 0); - require(firstBidTime == 1 hours); - } - - function test_RefundPreviousBidder() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - - uint256 beforeBalance = address(bidder).balance; - - vm.prank(address(otherBidder)); - auctions.createBid{value: 2 ether}(address(token), 0); - - uint256 afterBalance = address(bidder).balance; - require(afterBalance - beforeBalance == 1 ether); - } - - function test_TransferNFTIntoEscrow() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0); - - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - - require(token.ownerOf(0) == address(auctions)); - } - - function test_ExtendAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0); - - vm.warp(5 minutes); - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - - vm.warp(55 minutes); - vm.prank(address(otherBidder)); - auctions.createBid{value: 2 ether}(address(token), 0); - - (, , , , , uint256 newDuration, , ) = auctions.auctionForNFT(address(token), 0); - - require(newDuration == 1 hours + 5 minutes); - } - - function testRevert_MustApproveModule() public { - seller.setApprovalForModule(address(auctions), false); - - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0); - - vm.prank(address(bidder)); - vm.expectRevert("module has not been approved by user"); - auctions.createBid{value: 1 ether}(address(token), 0); - } - - function testRevert_SellerMustApproveERC721TransferHelper() public { - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), false); - - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0); - - vm.prank(address(bidder)); - vm.expectRevert("ERC721: transfer caller is not owner nor approved"); - auctions.createBid{value: 1 ether}(address(token), 0); - } - - function testRevert_InvalidTransferBeforeFirstBid() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0); - - vm.prank(address(seller)); - token.transferFrom(address(seller), address(otherBidder), 0); - - vm.prank(address(bidder)); - vm.expectRevert("ERC721: transfer caller is not owner nor approved"); - auctions.createBid{value: 1 ether}(address(token), 0); - } - - function testRevert_CannotBidOnExpiredAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 10 hours, 1 ether, address(sellerFundsRecipient), 0); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - - vm.warp(12 hours); - - vm.prank(address(otherBidder)); - vm.expectRevert("AUCTION_OVER"); - auctions.createBid{value: 2 ether}(address(token), 0); - } - - function testRevert_CannotBidOnAuctionNotStarted() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 1 days); - - vm.prank(address(bidder)); - vm.expectRevert("AUCTION_NOT_STARTED"); - auctions.createBid(address(token), 0); - } - - function testRevert_CannotBidOnAuctionNotActive() public { - vm.expectRevert("AUCTION_DOES_NOT_EXIST"); - auctions.createBid(address(token), 0); - } - - function testRevert_BidMustMeetReservePrice() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0); - - vm.prank(address(bidder)); - vm.expectRevert("RESERVE_PRICE_NOT_MET"); - auctions.createBid{value: 0.5 ether}(address(token), 0); - } - - function testRevert_BidMustBe10PercentGreaterThanPrevious() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - - vm.warp(1 hours + 1 minutes); - - vm.prank(address(otherBidder)); - vm.expectRevert("MINIMUM_BID_NOT_MET"); - auctions.createBid{value: 1.01 ether}(address(token), 0); - } - - /// /// - /// SETTLE AUCTION /// - /// /// - - function test_SettleAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - - vm.warp(10 hours); - vm.prank(address(otherBidder)); - auctions.createBid{value: 5 ether}(address(token), 0); - - vm.warp(1 days + 1 hours); - auctions.settleAuction(address(token), 0); - - require(token.ownerOf(0) == address(otherBidder)); - } - - function testRevert_AuctionNotStarted() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0); - - vm.expectRevert("AUCTION_NOT_STARTED"); - auctions.settleAuction(address(token), 0); - } - - function testRevert_AuctionNotOver() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - - vm.expectRevert("AUCTION_NOT_OVER"); - auctions.settleAuction(address(token), 0); - } -} diff --git a/contracts/test/modules/ReserveAuction/Finders/ERC20/ReserveAuctionFindersErc20.integration.t.sol b/contracts/test/modules/ReserveAuction/Finders/ERC20/ReserveAuctionFindersErc20.integration.t.sol deleted file mode 100644 index 31ff18e5..00000000 --- a/contracts/test/modules/ReserveAuction/Finders/ERC20/ReserveAuctionFindersErc20.integration.t.sol +++ /dev/null @@ -1,173 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {ReserveAuctionFindersErc20} from "../../../../../modules/ReserveAuction/Finders/ERC20/ReserveAuctionFindersErc20.sol"; -import {Zorb} from "../../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../../utils/modules/RoyaltyEngine.sol"; -import {TestERC721} from "../../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../../utils/tokens/WETH.sol"; -import {VM} from "../../../../utils/VM.sol"; - -/// @title ReserveAuctionFindersErc20IntegrationTest -/// @notice Integration Tests for Reserve Auction Finders ERC-20 -contract ReserveAuctionFindersErc20IntegrationTest is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - ReserveAuctionFindersErc20 internal auctions; - TestERC721 internal token; - WETH internal weth; - - Zorb internal seller; - Zorb internal sellerFundsRecipient; - Zorb internal finder; - Zorb internal royaltyRecipient; - Zorb internal bidder; - Zorb internal otherBidder; - Zorb internal protocolFeeRecipient; - - function setUp() public { - // Cheatcodes - vm = VM(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - seller = new Zorb(address(ZMM)); - sellerFundsRecipient = new Zorb(address(ZMM)); - bidder = new Zorb(address(ZMM)); - otherBidder = new Zorb(address(ZMM)); - finder = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - protocolFeeRecipient = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - token = new TestERC721(); - weth = new WETH(); - - // Deploy Reserve Auction Finders ERC-20 - auctions = new ReserveAuctionFindersErc20( - address(erc20TransferHelper), - address(erc721TransferHelper), - address(royaltyEngine), - address(ZPFS), - address(weth) - ); - registrar.registerModule(address(auctions)); - - // Set module fee - vm.prank(address(registrar)); - ZPFS.setFeeParams(address(auctions), address(protocolFeeRecipient), 1); - - // Set balances - vm.deal(address(seller), 100 ether); - vm.deal(address(bidder), 100 ether); - vm.deal(address(otherBidder), 100 ether); - - // Mint seller token - token.mint(address(seller), 0); - - // Bidder swap 50 ETH <> 50 WETH - vm.prank(address(bidder)); - weth.deposit{value: 50 ether}(); - - // otherBidder swap 50 ETH <> 50 WETH - vm.prank(address(otherBidder)); - weth.deposit{value: 50 ether}(); - - // Users approve module - seller.setApprovalForModule(address(auctions), true); - bidder.setApprovalForModule(address(auctions), true); - otherBidder.setApprovalForModule(address(auctions), true); - - // Seller approve ERC721TransferHelper - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - - // Bidder approve ERC20TransferHelper - vm.prank(address(bidder)); - weth.approve(address(erc20TransferHelper), 50 ether); - - // otherBidder approve ERC20TransferHelper - vm.prank(address(otherBidder)); - weth.approve(address(erc20TransferHelper), 50 ether); - } - - function runERC20() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 0.1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 0.1 ether, address(finder)); - - vm.warp(10 hours); - vm.prank(address(otherBidder)); - auctions.createBid(address(token), 0, 0.5 ether, address(finder)); - - vm.warp(1 days); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - - vm.warp(1 days + 1 hours); - auctions.settleAuction(address(token), 0); - } - - function test_ERC20Integration() public { - uint256 beforeSellerBalance = weth.balanceOf(address(sellerFundsRecipient)); - uint256 beforeBidderBalance = weth.balanceOf(address(bidder)); - uint256 beforeOtherBidderBalance = weth.balanceOf(address(otherBidder)); - uint256 beforeRoyaltyRecipientBalance = weth.balanceOf(address(royaltyRecipient)); - uint256 beforeFinderBalance = weth.balanceOf(address(finder)); - uint256 beforeProtocolFeeRecipient = weth.balanceOf(address(protocolFeeRecipient)); - address beforeTokenOwner = token.ownerOf(0); - - runERC20(); - - uint256 afterSellerBalance = weth.balanceOf(address(sellerFundsRecipient)); - uint256 afterBidderBalance = weth.balanceOf(address(bidder)); - uint256 afterOtherBidderBalance = weth.balanceOf(address(otherBidder)); - uint256 afterRoyaltyRecipientBalance = weth.balanceOf(address(royaltyRecipient)); - uint256 afterFinderBalance = weth.balanceOf(address(finder)); - uint256 afterProtocolFeeRecipient = weth.balanceOf(address(protocolFeeRecipient)); - address afterTokenOwner = token.ownerOf(0); - - // 1 WETH withdrawn from winning bidder - require((beforeBidderBalance - afterBidderBalance) == 1 ether); - // Losing bidder refunded - require(beforeOtherBidderBalance == afterOtherBidderBalance); - // 0.05 WETH creator royalty - require((afterRoyaltyRecipientBalance - beforeRoyaltyRecipientBalance) == 0.05 ether); - // 1 bps protocol fee (Remaining 0.95 ETH * 0.01% protocol fee = 0.000095 ETH) - require((afterProtocolFeeRecipient - beforeProtocolFeeRecipient) == 0.000095 ether); - // 1000 bps finders fee (Remaining 0.949905 ETH * 10% finders fee = 0.0949905 ETH) - require((afterFinderBalance - beforeFinderBalance) == 0.0949905 ether); - // Remaining 0.8549145 ETH paid to seller - require((afterSellerBalance - beforeSellerBalance) == 0.8549145 ether); - // NFT transferred to winning bidder - require(beforeTokenOwner == address(seller) && afterTokenOwner == address(bidder)); - } -} diff --git a/contracts/test/modules/ReserveAuction/Finders/ERC20/ReserveAuctionFindersErc20.t.sol b/contracts/test/modules/ReserveAuction/Finders/ERC20/ReserveAuctionFindersErc20.t.sol deleted file mode 100644 index cf961184..00000000 --- a/contracts/test/modules/ReserveAuction/Finders/ERC20/ReserveAuctionFindersErc20.t.sol +++ /dev/null @@ -1,492 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {ReserveAuctionFindersErc20} from "../../../../../modules/ReserveAuction/Finders/ERC20/ReserveAuctionFindersErc20.sol"; -import {Zorb} from "../../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../../utils/modules/RoyaltyEngine.sol"; -import {TestERC20} from "../../../../utils/tokens/TestERC20.sol"; -import {TestERC721} from "../../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../../utils/tokens/WETH.sol"; -import {VM} from "../../../../utils/VM.sol"; - -/// @title ReserveAuctionFindersErc20Test -/// @notice Unit Tests for Reserve Auction Finders ERC-20 -contract ReserveAuctionFindersErc20Test is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - ReserveAuctionFindersErc20 internal auctions; - TestERC20 internal erc20; - TestERC721 internal token; - WETH internal weth; - - Zorb internal seller; - Zorb internal sellerFundsRecipient; - Zorb internal operator; - Zorb internal finder; - Zorb internal royaltyRecipient; - Zorb internal bidder; - Zorb internal otherBidder; - - function setUp() public { - // Cheatcodes - vm = VM(HEVM_ADDRESS); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - seller = new Zorb(address(ZMM)); - sellerFundsRecipient = new Zorb(address(ZMM)); - operator = new Zorb(address(ZMM)); - bidder = new Zorb(address(ZMM)); - otherBidder = new Zorb(address(ZMM)); - finder = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - erc20 = new TestERC20(); - token = new TestERC721(); - weth = new WETH(); - - // Deploy Reserve Auction Finders ERC-20 - auctions = new ReserveAuctionFindersErc20( - address(erc20TransferHelper), - address(erc721TransferHelper), - address(royaltyEngine), - address(ZPFS), - address(weth) - ); - registrar.registerModule(address(auctions)); - - // Set balances - vm.deal(address(seller), 100 ether); - vm.deal(address(bidder), 100 ether); - vm.deal(address(otherBidder), 100 ether); - - // Mint seller token - token.mint(address(seller), 0); - - // Mint bidder 2^96 ERC-20 tokens - erc20.mint(address(bidder), 2**96); - - // Bidder swap 50 ETH <> 50 WETH - vm.prank(address(bidder)); - weth.deposit{value: 50 ether}(); - - // otherBidder swap 50 ETH <> 50 WETH - vm.prank(address(otherBidder)); - weth.deposit{value: 50 ether}(); - - // Users approve ReserveAuction module - seller.setApprovalForModule(address(auctions), true); - bidder.setApprovalForModule(address(auctions), true); - otherBidder.setApprovalForModule(address(auctions), true); - - // Seller approve ERC721TransferHelper - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - - // Bidder approve ERC20TransferHelper for TestERC20 - vm.prank(address(bidder)); - erc20.approve(address(erc20TransferHelper), 2**96); - - // Bidder approve ERC20TransferHelper for WETH - vm.prank(address(bidder)); - weth.approve(address(erc20TransferHelper), 50 ether); - - // otherBidder approve ERC20TransferHelper - vm.prank(address(otherBidder)); - weth.approve(address(erc20TransferHelper), 50 ether); - } - - /// /// - /// CREATE AUCTION /// - /// /// - - function test_CreateAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - ( - address creator, - address fundsRecipient, - uint256 reservePrice, - uint256 highestBid, - address highestBidder, - uint256 startTime, - address currency, - uint256 firstBidTime, - address referrer, - uint256 duration, - uint256 findersFeeBps - ) = auctions.auctionForNFT(address(token), 0); - - require(creator == address(seller)); - require(reservePrice == 1 ether); - require(fundsRecipient == address(sellerFundsRecipient)); - require(highestBid == 0 ether); - require(highestBidder == address(0)); - require(duration == 1 days); - require(startTime == 0); - require(currency == address(weth)); - require(firstBidTime == 0); - require(referrer == address(0)); - require(findersFeeBps == 1000); - } - - function test_CreateFutureAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 1 days, address(weth), 1000); - - (, , , , , uint256 startTime, , , , , ) = auctions.auctionForNFT(address(token), 0); - - require(startTime == 1 days); - } - - function test_CreateAuctionAndCancelPrevious() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.prank(address(seller)); - token.transferFrom(address(seller), address(sellerFundsRecipient), 0); - - sellerFundsRecipient.setApprovalForModule(address(auctions), true); - - vm.startPrank(address(sellerFundsRecipient)); - token.setApprovalForAll(address(erc721TransferHelper), true); - auctions.createAuction(address(token), 0, 5 days, 12 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - vm.stopPrank(); - - (address creator, , uint256 reservePrice, , , , , , , uint256 duration, ) = auctions.auctionForNFT(address(token), 0); - - require(creator == address(sellerFundsRecipient)); - require(duration == 5 days); - require(reservePrice == 12 ether); - } - - function testRevert_MustBeTokenOwnerOrOperator() public { - vm.expectRevert("ONLY_TOKEN_OWNER_OR_OPERATOR"); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - } - - function testRevert_FindersFeeBPSCannotExceed10000() public { - vm.prank(address(seller)); - vm.expectRevert("INVALID_FINDERS_FEE"); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth), 10001); - } - - function testRevert_MustSpecifySellerFundsRecipient() public { - vm.prank(address(seller)); - vm.expectRevert("INVALID_FUNDS_RECIPIENT"); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(0), 0, address(weth), 1000); - } - - /// /// - /// UPDATE RESERVE PRICE /// - /// /// - - function test_SetReservePrice() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.prank(address(seller)); - auctions.setAuctionReservePrice(address(token), 0, 5 ether); - - (, , uint256 reservePrice, , , , , , , , ) = auctions.auctionForNFT(address(token), 0); - require(reservePrice == 5 ether); - } - - function testRevert_UpdateMustBeSeller() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.expectRevert("ONLY_SELLER"); - auctions.setAuctionReservePrice(address(token), 0, 5 ether); - } - - function testRevert_CannotUpdateAuctionDoesNotExist() public { - vm.expectRevert("ONLY_SELLER"); - auctions.setAuctionReservePrice(address(token), 0, 5 ether); - } - - function testRevert_CannotUpdateActiveAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 5 ether, address(finder)); - - vm.prank(address(seller)); - vm.expectRevert("AUCTION_STARTED"); - auctions.setAuctionReservePrice(address(token), 0, 20 ether); - } - - /// /// - /// CANCEL AUCTION /// - /// /// - - function test_CancelAuction() public { - vm.startPrank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.warp(1 minutes); - - auctions.cancelAuction(address(token), 0); - vm.stopPrank(); - - (address creator, , , , , , , , , , ) = auctions.auctionForNFT(address(token), 0); - require(creator == address(0)); - } - - function testRevert_OnlySellerOrOwnerCanCancel() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.expectRevert("ONLY_SELLER_OR_TOKEN_OWNER"); - auctions.cancelAuction(address(token), 0); - } - - function testRevert_CannotCancelActiveAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - - vm.prank(address(seller)); - vm.expectRevert("AUCTION_STARTED"); - auctions.cancelAuction(address(token), 0); - } - - /// /// - /// CREATE BID /// - /// /// - - function test_CreateFirstBid() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - } - - function test_StoreTimeOfFirstBid() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - - (, , , , , , , uint256 firstBidTime, , , ) = auctions.auctionForNFT(address(token), 0); - - require(firstBidTime == 1 hours); - } - - function test_RefundPreviousBidder() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - - uint256 beforeBalance = weth.balanceOf(address(bidder)); - - vm.prank(address(otherBidder)); - auctions.createBid(address(token), 0, 2 ether, address(finder)); - - uint256 afterBalance = weth.balanceOf(address(bidder)); - - require(afterBalance - beforeBalance == 1 ether); - } - - function test_TransferNFTIntoEscrow() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - require(token.ownerOf(0) == address(auctions)); - } - - function test_ExtendAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.warp(5 minutes); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - - vm.warp(55 minutes); - vm.prank(address(otherBidder)); - auctions.createBid(address(token), 0, 2 ether, address(finder)); - - (, , , , , , , , , uint256 newDuration, ) = auctions.auctionForNFT(address(token), 0); - - require(newDuration == 1 hours + 5 minutes); - } - - function testRevert_MustApproveModule() public { - seller.setApprovalForModule(address(auctions), false); - - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.prank(address(bidder)); - vm.expectRevert("module has not been approved by user"); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - } - - function testRevert_SellerMustApproveERC721TransferHelper() public { - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), false); - - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.prank(address(bidder)); - vm.expectRevert("ERC721: transfer caller is not owner nor approved"); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - } - - function testRevert_InvalidTransferBeforeFirstBid() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.prank(address(seller)); - token.transferFrom(address(seller), address(otherBidder), 0); - - vm.prank(address(bidder)); - vm.expectRevert("ERC721: transfer caller is not owner nor approved"); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - } - - function testRevert_CannotBidOnExpiredAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 10 hours, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - - vm.warp(12 hours); - - vm.prank(address(otherBidder)); - vm.expectRevert("AUCTION_OVER"); - auctions.createBid(address(token), 0, 2 ether, address(finder)); - } - - function testRevert_CannotBidOnAuctionNotStarted() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 1 days, address(weth), 1000); - - vm.prank(address(bidder)); - vm.expectRevert("AUCTION_NOT_STARTED"); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - } - - function testRevert_CannotBidOnNonExistentAuction() public { - vm.expectRevert("AUCTION_DOES_NOT_EXIST"); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - } - - function testRevert_BidMustMeetReservePrice() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.prank(address(bidder)); - vm.expectRevert("RESERVE_PRICE_NOT_MET"); - auctions.createBid(address(token), 0, 0.5 ether, address(finder)); - } - - function testRevert_BidMustBe10PercentGreaterThanPrevious() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - - vm.warp(1 hours + 1 minutes); - - vm.prank(address(otherBidder)); - vm.expectRevert("MINIMUM_BID_NOT_MET"); - auctions.createBid(address(token), 0, 1.01 ether, address(finder)); - } - - /// /// - /// SETTLE AUCTION /// - /// /// - - function test_SettleAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - - vm.warp(10 hours); - - vm.prank(address(otherBidder)); - auctions.createBid(address(token), 0, 5 ether, address(finder)); - - vm.warp(1 days + 1 hours); - auctions.settleAuction(address(token), 0); - - require(token.ownerOf(0) == address(otherBidder)); - } - - function testRevert_AuctionNotStarted() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.expectRevert("AUCTION_NOT_STARTED"); - auctions.settleAuction(address(token), 0); - } - - function testRevert_AuctionNotOver() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, address(weth), 1000); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - - vm.warp(10 hours); - - vm.expectRevert("AUCTION_NOT_OVER"); - auctions.settleAuction(address(token), 0); - } -} diff --git a/contracts/test/modules/ReserveAuction/Finders/ETH/ReserveAuctionFindersEth.integration.t.sol b/contracts/test/modules/ReserveAuction/Finders/ETH/ReserveAuctionFindersEth.integration.t.sol deleted file mode 100644 index c1715489..00000000 --- a/contracts/test/modules/ReserveAuction/Finders/ETH/ReserveAuctionFindersEth.integration.t.sol +++ /dev/null @@ -1,163 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {ReserveAuctionFindersEth} from "../../../../../modules/ReserveAuction/Finders/ETH/ReserveAuctionFindersEth.sol"; -import {Zorb} from "../../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../../utils/modules/RoyaltyEngine.sol"; -import {TestERC721} from "../../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../../utils/tokens/WETH.sol"; -import {VM} from "../../../../utils/VM.sol"; - -/// @title ReserveAuctionFindersEthIntegrationTest -/// @notice Integration Tests for Reserve Auction Finders ETH -contract ReserveAuctionFindersEthIntegrationTest is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - ReserveAuctionFindersEth internal auctions; - TestERC721 internal token; - WETH internal weth; - - Zorb internal seller; - Zorb internal sellerFundsRecipient; - Zorb internal operator; - Zorb internal bidder; - Zorb internal otherBidder; - Zorb internal finder; - Zorb internal lister; - Zorb internal royaltyRecipient; - Zorb internal protocolFeeRecipient; - - function setUp() public { - // Cheatcodes - vm = VM(HEVM_ADDRESS); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - seller = new Zorb(address(ZMM)); - sellerFundsRecipient = new Zorb(address(ZMM)); - operator = new Zorb(address(ZMM)); - bidder = new Zorb(address(ZMM)); - otherBidder = new Zorb(address(ZMM)); - finder = new Zorb(address(ZMM)); - lister = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - protocolFeeRecipient = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - token = new TestERC721(); - weth = new WETH(); - - // Deploy Reserve Auction Finders ETH - auctions = new ReserveAuctionFindersEth(address(erc721TransferHelper), address(royaltyEngine), address(ZPFS), address(weth)); - registrar.registerModule(address(auctions)); - - // Set module fee - vm.prank(address(registrar)); - ZPFS.setFeeParams(address(auctions), address(protocolFeeRecipient), 1); - - // Set balances - vm.deal(address(seller), 100 ether); - vm.deal(address(bidder), 100 ether); - vm.deal(address(otherBidder), 100 ether); - - // Mint seller token - token.mint(address(seller), 0); - - // Bidder swap 50 ETH <> 50 WETH - vm.prank(address(bidder)); - weth.deposit{value: 50 ether}(); - - // otherBidder swap 50 ETH <> 50 WETH - vm.prank(address(otherBidder)); - weth.deposit{value: 50 ether}(); - - // Users approve module - seller.setApprovalForModule(address(auctions), true); - bidder.setApprovalForModule(address(auctions), true); - otherBidder.setApprovalForModule(address(auctions), true); - - // Seller approve ERC721TransferHelper - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - } - - function runETH() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 0.1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid{value: 0.1 ether}(address(token), 0, address(finder)); - - vm.warp(10 hours); - vm.prank(address(otherBidder)); - auctions.createBid{value: 0.5 ether}(address(token), 0, address(finder)); - - vm.warp(1 days); - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0, address(finder)); - - vm.warp(1 days + 1 hours); - auctions.settleAuction(address(token), 0); - } - - function test_ETHIntegration() public { - uint256 beforeSellerBalance = address(sellerFundsRecipient).balance; - uint256 beforeBidderBalance = address(bidder).balance; - uint256 beforeOtherBidderBalance = address(otherBidder).balance; - uint256 beforeRoyaltyRecipientBalance = address(royaltyRecipient).balance; - uint256 beforeFinderBalance = address(finder).balance; - uint256 beforeProtocolFeeRecipient = address(protocolFeeRecipient).balance; - address beforeTokenOwner = token.ownerOf(0); - - runETH(); - - uint256 afterSellerBalance = address(sellerFundsRecipient).balance; - uint256 afterBidderBalance = address(bidder).balance; - uint256 afterOtherBidderBalance = address(otherBidder).balance; - uint256 afterRoyaltyRecipientBalance = address(royaltyRecipient).balance; - uint256 afterFinderBalance = address(finder).balance; - uint256 afterProtocolFeeRecipient = address(protocolFeeRecipient).balance; - address afterTokenOwner = token.ownerOf(0); - - // 1 ETH withdrawn from winning bidder - require((beforeBidderBalance - afterBidderBalance) == 1 ether); - // Losing bidder refunded - require(beforeOtherBidderBalance == afterOtherBidderBalance); - // 0.05 ETH creator royalty - require((afterRoyaltyRecipientBalance - beforeRoyaltyRecipientBalance) == 0.05 ether); - // 1 bps protocol fee (Remaining 0.95 ETH * 0.01% protocol fee = 0.000095 ETH) - require((afterProtocolFeeRecipient - beforeProtocolFeeRecipient) == 0.000095 ether); - // 1000 bps finders fee (Remaining 0.949905 ETH * 10% finders fee = 0.0949905 ETH) - require((afterFinderBalance - beforeFinderBalance) == 0.0949905 ether); - // Remaining 0.8549145 ETH paid to seller - require((afterSellerBalance - beforeSellerBalance) == 0.8549145 ether); - // NFT transferred to winning bidder - require(beforeTokenOwner == address(seller) && afterTokenOwner == address(bidder)); - } -} diff --git a/contracts/test/modules/ReserveAuction/Finders/ETH/ReserveAuctionFindersEth.t.sol b/contracts/test/modules/ReserveAuction/Finders/ETH/ReserveAuctionFindersEth.t.sol deleted file mode 100644 index a12cd338..00000000 --- a/contracts/test/modules/ReserveAuction/Finders/ETH/ReserveAuctionFindersEth.t.sol +++ /dev/null @@ -1,455 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {ReserveAuctionFindersEth} from "../../../../../modules/ReserveAuction/Finders/ETH/ReserveAuctionFindersEth.sol"; -import {Zorb} from "../../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../../utils/modules/RoyaltyEngine.sol"; -import {TestERC721} from "../../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../../utils/tokens/WETH.sol"; -import {VM} from "../../../../utils/VM.sol"; - -/// @title ReserveAuctionFindersEthTest -/// @notice Unit Tests for Reserve Auction Finders ETH -contract ReserveAuctionFindersEthTest is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - ReserveAuctionFindersEth internal auctions; - - TestERC721 internal token; - WETH internal weth; - Zorb internal seller; - Zorb internal sellerFundsRecipient; - Zorb internal operator; - Zorb internal bidder; - Zorb internal otherBidder; - Zorb internal finder; - Zorb internal lister; - Zorb internal royaltyRecipient; - - function setUp() public { - // Cheatcodes - vm = VM(HEVM_ADDRESS); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - seller = new Zorb(address(ZMM)); - sellerFundsRecipient = new Zorb(address(ZMM)); - operator = new Zorb(address(ZMM)); - bidder = new Zorb(address(ZMM)); - otherBidder = new Zorb(address(ZMM)); - finder = new Zorb(address(ZMM)); - lister = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - token = new TestERC721(); - weth = new WETH(); - - // Deploy Reserve Auction Finders ETH - auctions = new ReserveAuctionFindersEth(address(erc721TransferHelper), address(royaltyEngine), address(ZPFS), address(weth)); - registrar.registerModule(address(auctions)); - - // Set balances - vm.deal(address(seller), 100 ether); - vm.deal(address(bidder), 100 ether); - vm.deal(address(otherBidder), 100 ether); - - // Mint seller token - token.mint(address(seller), 0); - - // Users approve module - seller.setApprovalForModule(address(auctions), true); - bidder.setApprovalForModule(address(auctions), true); - otherBidder.setApprovalForModule(address(auctions), true); - - // Seller approve ERC721TransferHelper - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - } - - /// /// - /// CREATE AUCTION /// - /// /// - - function test_CreateAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000); - - ( - address creator, - uint256 reservePrice, - address fundsRecipient, - uint256 highestBid, - address highestBidder, - uint256 duration, - uint256 startTime, - address highestBidfinder, - uint256 firstBidTime, - uint256 findersFeeBps - ) = auctions.auctionForNFT(address(token), 0); - - require(creator == address(seller)); - require(reservePrice == 1 ether); - require(fundsRecipient == address(sellerFundsRecipient)); - require(highestBid == 0 ether); - require(highestBidder == address(0)); - require(duration == 1 days); - require(startTime == 0); - require(highestBidfinder == address(0)); - require(findersFeeBps == 1000); - require(firstBidTime == 0); - } - - function test_CreateFutureAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 1 days, 1000); - - (, , , , , , uint256 startTime, , , ) = auctions.auctionForNFT(address(token), 0); - require(startTime == 1 days); - } - - function test_CreateAuctionAndCancelPrevious() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.prank(address(seller)); - token.transferFrom(address(seller), address(sellerFundsRecipient), 0); - - sellerFundsRecipient.setApprovalForModule(address(auctions), true); - - vm.startPrank(address(sellerFundsRecipient)); - token.setApprovalForAll(address(erc721TransferHelper), true); - auctions.createAuction(address(token), 0, 5 days, 12 ether, address(sellerFundsRecipient), 0, 1000); - vm.stopPrank(); - - (address creator, uint256 reservePrice, , , , uint256 duration, , , , ) = auctions.auctionForNFT(address(token), 0); - require(creator == address(sellerFundsRecipient)); - require(duration == 5 days); - require(reservePrice == 12 ether); - } - - function testRevert_MustBeTokenOwnerOrOperator() public { - vm.expectRevert("ONLY_TOKEN_OWNER_OR_OPERATOR"); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000); - } - - function testRevert_FindersFeeBPSCannotExceed10000() public { - vm.prank(address(seller)); - vm.expectRevert("INVALID_FINDERS_FEE"); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 10001); - } - - function testRevert_MustSpecifySellerFundsRecipient() public { - vm.prank(address(seller)); - vm.expectRevert("INVALID_FUNDS_RECIPIENT"); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(0), 0, 1000); - } - - /// /// - /// UPDATE RESERVE PRICE /// - /// /// - - function test_SetReservePrice() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.prank(address(seller)); - auctions.setAuctionReservePrice(address(token), 0, 5 ether); - - (, uint256 reservePrice, , , , , , , , ) = auctions.auctionForNFT(address(token), 0); - require(reservePrice == 5 ether); - } - - function testRevert_UpdateMustBeSeller() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.expectRevert("ONLY_SELLER"); - auctions.setAuctionReservePrice(address(token), 0, 5 ether); - } - - function testRevert_CannotUpdateAuctionDoesNotExist() public { - vm.expectRevert("ONLY_SELLER"); - auctions.setAuctionReservePrice(address(token), 0, 5 ether); - } - - function testRevert_CannotUpdateActiveAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid{value: 5 ether}(address(token), 0, address(finder)); - - vm.prank(address(seller)); - vm.expectRevert("AUCTION_STARTED"); - auctions.setAuctionReservePrice(address(token), 0, 20 ether); - } - - /// /// - /// CANCEL AUCTION /// - /// /// - - function test_CancelAuction() public { - vm.startPrank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.warp(1 minutes); - - auctions.cancelAuction(address(token), 0); - vm.stopPrank(); - - (address creator, , , , , , , , , ) = auctions.auctionForNFT(address(token), 0); - require(creator == address(0)); - } - - function testRevert_OnlySellerOrOwnerCanCancel() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.expectRevert("ONLY_SELLER_OR_TOKEN_OWNER"); - auctions.cancelAuction(address(token), 0); - } - - function testRevert_CannotCancelActiveAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0, address(finder)); - - vm.prank(address(seller)); - vm.expectRevert("AUCTION_STARTED"); - auctions.cancelAuction(address(token), 0); - } - - /// /// - /// CREATE BID /// - /// /// - - function test_CreateFirstBid() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000); - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0, address(finder)); - } - - function test_StoreTimeOfFirstBid() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0, address(finder)); - - (, , , , , , , , uint256 firstBidTime, ) = auctions.auctionForNFT(address(token), 0); - require(firstBidTime == 1 hours); - } - - function test_RefundPreviousBidder() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0, address(finder)); - uint256 beforeBalance = address(bidder).balance; - - vm.prank(address(otherBidder)); - auctions.createBid{value: 2 ether}(address(token), 0, address(finder)); - - uint256 afterBalance = address(bidder).balance; - - require(afterBalance - beforeBalance == 1 ether); - } - - function test_TransferNFTIntoEscrow() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000); - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0, address(finder)); - require(token.ownerOf(0) == address(auctions)); - } - - function test_ExtendAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.warp(5 minutes); - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0, address(finder)); - - vm.warp(55 minutes); - vm.prank(address(otherBidder)); - auctions.createBid{value: 2 ether}(address(token), 0, address(finder)); - - (, , , , , uint256 newDuration, , , , ) = auctions.auctionForNFT(address(token), 0); - - require(newDuration == 1 hours + 5 minutes); - } - - function testRevert_MustApproveModule() public { - seller.setApprovalForModule(address(auctions), false); - - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.prank(address(bidder)); - vm.expectRevert("module has not been approved by user"); - auctions.createBid{value: 1 ether}(address(token), 0, address(finder)); - } - - function testRevert_SellerMustApproveERC721TransferHelper() public { - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), false); - - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.prank(address(bidder)); - vm.expectRevert("ERC721: transfer caller is not owner nor approved"); - auctions.createBid{value: 1 ether}(address(token), 0, address(finder)); - } - - function testRevert_InvalidTransferBeforeFirstBid() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.prank(address(seller)); - token.transferFrom(address(seller), address(otherBidder), 0); - - vm.prank(address(bidder)); - vm.expectRevert("ERC721: transfer caller is not owner nor approved"); - auctions.createBid{value: 1 ether}(address(token), 0, address(finder)); - } - - function testRevert_CannotBidOnExpiredAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 10 hours, 1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0, address(finder)); - - vm.warp(12 hours); - - vm.prank(address(otherBidder)); - vm.expectRevert("AUCTION_OVER"); - auctions.createBid{value: 2 ether}(address(token), 0, address(finder)); - } - - function testRevert_CannotBidOnAuctionNotStarted() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 1 days, 1000); - - vm.prank(address(bidder)); - vm.expectRevert("AUCTION_NOT_STARTED"); - auctions.createBid(address(token), 0, address(finder)); - } - - function testRevert_CannotBidOnAuctionNotActive() public { - vm.expectRevert("AUCTION_DOES_NOT_EXIST"); - auctions.createBid{value: 1 ether}(address(token), 0, address(finder)); - } - - function testRevert_BidMustMeetReservePrice() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.prank(address(bidder)); - vm.expectRevert("RESERVE_PRICE_NOT_MET"); - auctions.createBid{value: 0.5 ether}(address(token), 0, address(finder)); - } - - function testRevert_BidMustBe10PercentGreaterThanPrevious() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0, address(finder)); - - vm.warp(1 hours + 1 minutes); - - vm.prank(address(otherBidder)); - vm.expectRevert("MINIMUM_BID_NOT_MET"); - auctions.createBid{value: 1.01 ether}(address(token), 0, address(finder)); - } - - /// /// - /// SETTLE AUCTION /// - /// /// - - function test_SettleAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0, address(finder)); - - vm.warp(10 hours); - - vm.prank(address(otherBidder)); - auctions.createBid{value: 5 ether}(address(token), 0, address(finder)); - - vm.warp(1 days + 1 hours); - auctions.settleAuction(address(token), 0); - - require(token.ownerOf(0) == address(otherBidder)); - } - - function testRevert_AuctionNotStarted() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.expectRevert("AUCTION_NOT_STARTED"); - auctions.settleAuction(address(token), 0); - } - - function testRevert_AuctionNotOver() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0, address(finder)); - - vm.warp(10 hours); - - vm.expectRevert("AUCTION_NOT_OVER"); - auctions.settleAuction(address(token), 0); - } -} diff --git a/contracts/test/modules/ReserveAuction/Listing/ETH/ReserveAuctionListingEth.integration.t.sol b/contracts/test/modules/ReserveAuction/Listing/ETH/ReserveAuctionListingEth.integration.t.sol deleted file mode 100644 index 8840d747..00000000 --- a/contracts/test/modules/ReserveAuction/Listing/ETH/ReserveAuctionListingEth.integration.t.sol +++ /dev/null @@ -1,160 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {ReserveAuctionListingEth} from "../../../../../modules/ReserveAuction/Listing/ETH/ReserveAuctionListingEth.sol"; -import {Zorb} from "../../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../../utils/modules/RoyaltyEngine.sol"; -import {TestERC721} from "../../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../../utils/tokens/WETH.sol"; -import {VM} from "../../../../utils/VM.sol"; - -/// @title ReserveAuctionListingEthIntegrationTest -/// @notice Integration Tests for Reserve Auction Listing ETH -contract ReserveAuctionListingEthIntegrationTest is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - ReserveAuctionListingEth internal auctions; - TestERC721 internal token; - WETH internal weth; - - Zorb internal seller; - Zorb internal sellerFundsRecipient; - Zorb internal operator; - Zorb internal bidder; - Zorb internal otherBidder; - Zorb internal listingFeeRecipient; - Zorb internal royaltyRecipient; - Zorb internal protocolFeeRecipient; - - function setUp() public { - // Cheatcodes - vm = VM(HEVM_ADDRESS); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - seller = new Zorb(address(ZMM)); - sellerFundsRecipient = new Zorb(address(ZMM)); - operator = new Zorb(address(ZMM)); - bidder = new Zorb(address(ZMM)); - otherBidder = new Zorb(address(ZMM)); - listingFeeRecipient = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - protocolFeeRecipient = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - token = new TestERC721(); - weth = new WETH(); - - auctions = new ReserveAuctionListingEth(address(erc721TransferHelper), address(royaltyEngine), address(ZPFS), address(weth)); - registrar.registerModule(address(auctions)); - - // Set module fee - vm.prank(address(registrar)); - ZPFS.setFeeParams(address(auctions), address(protocolFeeRecipient), 1); - - // Set balances - vm.deal(address(seller), 100 ether); - vm.deal(address(bidder), 100 ether); - vm.deal(address(otherBidder), 100 ether); - - // Mint seller token - token.mint(address(seller), 0); - - // Bidder swap 50 ETH <> 50 WETH - vm.prank(address(bidder)); - weth.deposit{value: 50 ether}(); - - // otherBidder swap 50 ETH <> 50 WETH - vm.prank(address(otherBidder)); - weth.deposit{value: 50 ether}(); - - // Users approve module - seller.setApprovalForModule(address(auctions), true); - bidder.setApprovalForModule(address(auctions), true); - otherBidder.setApprovalForModule(address(auctions), true); - - // Seller approve ERC721TransferHelper - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - } - - function runETH() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 0.1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid{value: 0.1 ether}(address(token), 0); - - vm.warp(10 hours); - vm.prank(address(otherBidder)); - auctions.createBid{value: 0.5 ether}(address(token), 0); - - vm.warp(1 days); - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - - vm.warp(1 days + 1 hours); - auctions.settleAuction(address(token), 0); - } - - function test_ETHIntegration() public { - uint256 beforeSellerBalance = address(sellerFundsRecipient).balance; - uint256 beforeBidderBalance = address(bidder).balance; - uint256 beforeOtherBidderBalance = address(otherBidder).balance; - uint256 beforeRoyaltyRecipientBalance = address(royaltyRecipient).balance; - uint256 beforelistingFeeRecipientBalance = address(listingFeeRecipient).balance; - uint256 beforeProtocolFeeRecipient = address(protocolFeeRecipient).balance; - address beforeTokenOwner = token.ownerOf(0); - - runETH(); - - uint256 afterSellerBalance = address(sellerFundsRecipient).balance; - uint256 afterBidderBalance = address(bidder).balance; - uint256 afterOtherBidderBalance = address(otherBidder).balance; - uint256 afterRoyaltyRecipientBalance = address(royaltyRecipient).balance; - uint256 afterlistingFeeRecipientBalance = address(listingFeeRecipient).balance; - uint256 afterProtocolFeeRecipient = address(protocolFeeRecipient).balance; - address afterTokenOwner = token.ownerOf(0); - - // 1 ETH withdrawn from winning bidder - require((beforeBidderBalance - afterBidderBalance) == 1 ether); - // Losing bidder refunded - require(beforeOtherBidderBalance == afterOtherBidderBalance); - // 0.05 ETH creator royalty - require((afterRoyaltyRecipientBalance - beforeRoyaltyRecipientBalance) == 0.05 ether); - // 1 bps protocol fee (Remaining 0.95 ETH * 0.01% protocol fee = 0.000095 ETH) - require((afterProtocolFeeRecipient - beforeProtocolFeeRecipient) == 0.000095 ether); - // 1000 bps listing fee (Remaining 0.949905 ETH * 10% listing fee = 0.0949905 ETH) - require((afterlistingFeeRecipientBalance - beforelistingFeeRecipientBalance) == 0.0949905 ether); - // Remaining 0.8549145 ETH paid to seller - require((afterSellerBalance - beforeSellerBalance) == 0.8549145 ether); - // NFT transferred to winning bidder - require(beforeTokenOwner == address(seller) && afterTokenOwner == address(bidder)); - } -} diff --git a/contracts/test/modules/ReserveAuction/Listing/ETH/ReserveAuctionListingEth.t.sol b/contracts/test/modules/ReserveAuction/Listing/ETH/ReserveAuctionListingEth.t.sol deleted file mode 100644 index 56d40416..00000000 --- a/contracts/test/modules/ReserveAuction/Listing/ETH/ReserveAuctionListingEth.t.sol +++ /dev/null @@ -1,453 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {ReserveAuctionListingEth} from "../../../../../modules/ReserveAuction/Listing/ETH/ReserveAuctionListingEth.sol"; -import {Zorb} from "../../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../../utils/modules/RoyaltyEngine.sol"; -import {TestERC721} from "../../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../../utils/tokens/WETH.sol"; -import {VM} from "../../../../utils/VM.sol"; - -/// @title ReserveAuctionListingEthTest -/// @notice Unit Tests for Reserve Auction Listing ETH -contract ReserveAuctionListingEthTest is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - ReserveAuctionListingEth internal auctions; - - TestERC721 internal token; - WETH internal weth; - Zorb internal seller; - Zorb internal sellerFundsRecipient; - Zorb internal operator; - Zorb internal bidder; - Zorb internal otherBidder; - Zorb internal listingFeeRecipient; - Zorb internal royaltyRecipient; - - function setUp() public { - // Cheatcodes - vm = VM(HEVM_ADDRESS); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - seller = new Zorb(address(ZMM)); - sellerFundsRecipient = new Zorb(address(ZMM)); - operator = new Zorb(address(ZMM)); - bidder = new Zorb(address(ZMM)); - otherBidder = new Zorb(address(ZMM)); - listingFeeRecipient = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - token = new TestERC721(); - weth = new WETH(); - - // Deploy Reserve Auction Listing ETH - auctions = new ReserveAuctionListingEth(address(erc721TransferHelper), address(royaltyEngine), address(ZPFS), address(weth)); - registrar.registerModule(address(auctions)); - - // Set balances - vm.deal(address(seller), 100 ether); - vm.deal(address(bidder), 100 ether); - vm.deal(address(otherBidder), 100 ether); - - // Mint seller token - token.mint(address(seller), 0); - - // Users approve module - seller.setApprovalForModule(address(auctions), true); - bidder.setApprovalForModule(address(auctions), true); - otherBidder.setApprovalForModule(address(auctions), true); - - // Seller approve ERC721TransferHelper - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - } - - /// /// - /// CREATE AUCTION /// - /// /// - - function test_CreateAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - ( - address creator, - uint256 reservePrice, - address fundsRecipient, - uint256 highestBid, - address highestBidder, - uint256 duration, - uint256 startTime, - address lister, - uint256 firstBidTime, - uint256 listingFeeBps - ) = auctions.auctionForNFT(address(token), 0); - - require(creator == address(seller)); - require(reservePrice == 1 ether); - require(fundsRecipient == address(sellerFundsRecipient)); - require(highestBid == 0 ether); - require(highestBidder == address(0)); - require(duration == 1 days); - require(startTime == 0); - require(lister == address(listingFeeRecipient)); - require(listingFeeBps == 1000); - require(firstBidTime == 0); - } - - function test_CreateFutureAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 1 days, 1000, address(listingFeeRecipient)); - - (, , , , , , uint256 startTime, , , ) = auctions.auctionForNFT(address(token), 0); - require(startTime == 1 days); - } - - function test_CreateAuctionAndCancelPrevious() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.prank(address(seller)); - token.transferFrom(address(seller), address(sellerFundsRecipient), 0); - - sellerFundsRecipient.setApprovalForModule(address(auctions), true); - - vm.startPrank(address(sellerFundsRecipient)); - token.setApprovalForAll(address(erc721TransferHelper), true); - auctions.createAuction(address(token), 0, 5 days, 12 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - vm.stopPrank(); - - (address creator, uint256 reservePrice, , , , uint256 duration, , , , ) = auctions.auctionForNFT(address(token), 0); - require(creator == address(sellerFundsRecipient)); - require(duration == 5 days); - require(reservePrice == 12 ether); - } - - function testRevert_MustBeTokenOwnerOrOperator() public { - vm.expectRevert("ONLY_TOKEN_OWNER_OR_OPERATOR"); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - } - - function testRevert_ListingFeeBPSCannotExceed10000() public { - vm.prank(address(seller)); - vm.expectRevert("INVALID_LISTING_FEE"); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 10001, address(listingFeeRecipient)); - } - - function testRevert_MustSpecifySellerFundsRecipient() public { - vm.prank(address(seller)); - vm.expectRevert("INVALID_FUNDS_RECIPIENT"); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(0), 0, 1000, address(listingFeeRecipient)); - } - - /// /// - /// UPDATE RESERVE PRICE /// - /// /// - - function test_SetReservePrice() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.prank(address(seller)); - auctions.setAuctionReservePrice(address(token), 0, 5 ether); - - (, uint256 reservePrice, , , , , , , , ) = auctions.auctionForNFT(address(token), 0); - require(reservePrice == 5 ether); - } - - function testRevert_UpdateMustBeSeller() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.expectRevert("ONLY_SELLER"); - auctions.setAuctionReservePrice(address(token), 0, 5 ether); - } - - function testRevert_CannotUpdateAuctionDoesNotExist() public { - vm.expectRevert("ONLY_SELLER"); - auctions.setAuctionReservePrice(address(token), 0, 5 ether); - } - - function testRevert_CannotUpdateActiveAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid{value: 5 ether}(address(token), 0); - - vm.prank(address(seller)); - vm.expectRevert("AUCTION_STARTED"); - auctions.setAuctionReservePrice(address(token), 0, 20 ether); - } - - /// /// - /// CANCEL AUCTION /// - /// /// - - function test_CancelAuction() public { - vm.startPrank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.warp(1 minutes); - - auctions.cancelAuction(address(token), 0); - vm.stopPrank(); - - (address creator, , , , , , , , , ) = auctions.auctionForNFT(address(token), 0); - require(creator == address(0)); - } - - function testRevert_OnlySellerOrOwnerCanCancel() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.expectRevert("ONLY_SELLER_OR_TOKEN_OWNER"); - auctions.cancelAuction(address(token), 0); - } - - function testRevert_CannotCancelActiveAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - - vm.prank(address(seller)); - vm.expectRevert("AUCTION_STARTED"); - auctions.cancelAuction(address(token), 0); - } - - /// /// - /// CREATE BID /// - /// /// - - function test_CreateFirstBid() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - } - - function test_StoreTimeOfFirstBid() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - - (, , , , , , , , uint256 firstBidTime, ) = auctions.auctionForNFT(address(token), 0); - require(firstBidTime == 1 hours); - } - - function test_RefundPreviousBidder() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - uint256 beforeBalance = address(bidder).balance; - - vm.prank(address(otherBidder)); - auctions.createBid{value: 2 ether}(address(token), 0); - - uint256 afterBalance = address(bidder).balance; - - require(afterBalance - beforeBalance == 1 ether); - } - - function test_TransferNFTIntoEscrow() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - require(token.ownerOf(0) == address(auctions)); - } - - function test_ExtendAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.warp(5 minutes); - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - - vm.warp(55 minutes); - vm.prank(address(otherBidder)); - auctions.createBid{value: 2 ether}(address(token), 0); - - (, , , , , uint256 newDuration, , , , ) = auctions.auctionForNFT(address(token), 0); - - require(newDuration == 1 hours + 5 minutes); - } - - function testRevert_MustApproveModule() public { - seller.setApprovalForModule(address(auctions), false); - - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.prank(address(bidder)); - vm.expectRevert("module has not been approved by user"); - auctions.createBid{value: 1 ether}(address(token), 0); - } - - function testRevert_SellerMustApproveERC721TransferHelper() public { - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), false); - - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.prank(address(bidder)); - vm.expectRevert("ERC721: transfer caller is not owner nor approved"); - auctions.createBid{value: 1 ether}(address(token), 0); - } - - function testRevert_InvalidTransferBeforeFirstBid() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 hours, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.prank(address(seller)); - token.transferFrom(address(seller), address(otherBidder), 0); - - vm.prank(address(bidder)); - vm.expectRevert("ERC721: transfer caller is not owner nor approved"); - auctions.createBid{value: 1 ether}(address(token), 0); - } - - function testRevert_CannotBidOnExpiredAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 10 hours, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - - vm.warp(12 hours); - - vm.prank(address(otherBidder)); - vm.expectRevert("AUCTION_OVER"); - auctions.createBid{value: 2 ether}(address(token), 0); - } - - function testRevert_CannotBidOnAuctionNotStarted() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 1 days, 1000, address(listingFeeRecipient)); - - vm.prank(address(bidder)); - vm.expectRevert("AUCTION_NOT_STARTED"); - auctions.createBid(address(token), 0); - } - - function testRevert_CannotBidOnAuctionNotActive() public { - vm.expectRevert("AUCTION_DOES_NOT_EXIST"); - auctions.createBid{value: 1 ether}(address(token), 0); - } - - function testRevert_BidMustMeetReservePrice() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.prank(address(bidder)); - vm.expectRevert("RESERVE_PRICE_NOT_MET"); - auctions.createBid{value: 0.5 ether}(address(token), 0); - } - - function testRevert_BidMustBe10PercentGreaterThanPrevious() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - - vm.warp(1 hours + 1 minutes); - - vm.prank(address(otherBidder)); - vm.expectRevert("MINIMUM_BID_NOT_MET"); - auctions.createBid{value: 1.01 ether}(address(token), 0); - } - - /// /// - /// SETTLE AUCTION /// - /// /// - - function test_SettleAuction() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - - vm.warp(10 hours); - - vm.prank(address(otherBidder)); - auctions.createBid{value: 5 ether}(address(token), 0); - - vm.warp(1 days + 1 hours); - auctions.settleAuction(address(token), 0); - - require(token.ownerOf(0) == address(otherBidder)); - } - - function testRevert_AuctionNotStarted() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.expectRevert("AUCTION_NOT_STARTED"); - auctions.settleAuction(address(token), 0); - } - - function testRevert_AuctionNotOver() public { - vm.prank(address(seller)); - auctions.createAuction(address(token), 0, 1 days, 1 ether, address(sellerFundsRecipient), 0, 1000, address(listingFeeRecipient)); - - vm.warp(1 hours); - - vm.prank(address(bidder)); - auctions.createBid{value: 1 ether}(address(token), 0); - - vm.warp(10 hours); - - vm.expectRevert("AUCTION_NOT_OVER"); - auctions.settleAuction(address(token), 0); - } -} diff --git a/contracts/test/modules/ReserveAuction/Omnibus/ReserveAuctionDataStorage.t.sol b/contracts/test/modules/ReserveAuction/Omnibus/ReserveAuctionDataStorage.t.sol deleted file mode 100644 index a035dbd0..00000000 --- a/contracts/test/modules/ReserveAuction/Omnibus/ReserveAuctionDataStorage.t.sol +++ /dev/null @@ -1,114 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {ReserveAuctionDataStorage, FEATURE_MASK_LISTING_FEE, FEATURE_MASK_FINDERS_FEE, FEATURE_MASK_ERC20_CURRENCY, FEATURE_MASK_TOKEN_GATE, FEATURE_MASK_START_TIME, FEATURE_MASK_RECIPIENT_OR_EXPIRY} from "../../../../modules/ReserveAuction/Omnibus/ReserveAuctionDataStorage.sol"; -import {VM} from "../../../utils/VM.sol"; - -contract StorageTestBaseFull is ReserveAuctionDataStorage { - function newAuction(address tokenContract, uint256 tokenId) public { - StoredAuction storage auction = auctionForNFT[tokenContract][tokenId]; - auction.seller = address(0x001); - auction.reservePrice = 0.4 ether; - auction.duration = 2 hours; - _setERC20Currency(auction, address(0x002)); - _setTokenGate(auction, address(0x003), 0.1 ether); - _setStartTime(auction, uint96(block.timestamp) + 1 days); - _setListingFee(auction, 1, address(0x004)); - _setFindersFee(auction, 2, address(0)); - _setExpiryAndFundsRecipient(auction, uint96(block.timestamp) + 2 days, address(0x005)); - } - - function getExpectedActiveFeatures() public returns (uint32) { - return - FEATURE_MASK_LISTING_FEE | - FEATURE_MASK_FINDERS_FEE | - FEATURE_MASK_ERC20_CURRENCY | - FEATURE_MASK_TOKEN_GATE | - FEATURE_MASK_START_TIME | - FEATURE_MASK_RECIPIENT_OR_EXPIRY; - } - - function hasFeature(uint32 features, uint32 feature) public returns (bool) { - return _hasFeature(features, feature); - } - - function getFullAuction(address tokenContract, uint256 tokenId) public returns (FullAuction memory) { - return _getFullAuction(tokenContract, tokenId); - } -} - -contract StorageTestBaseMinimal is ReserveAuctionDataStorage { - function newAuction(address tokenContract, uint256 tokenId) public { - StoredAuction storage auction = auctionForNFT[tokenContract][tokenId]; - auction.seller = address(0x001); - auction.reservePrice = 0.4 ether; - auction.duration = 1000; - } - - function hasFeature(uint32 features, uint32 feature) public returns (bool) { - return _hasFeature(features, feature); - } - - function getFullAuction(address tokenContract, uint256 tokenId) public returns (FullAuction memory) { - return _getFullAuction(tokenContract, tokenId); - } -} - -/// @title -/// @notice -contract AuctionDataStorageTest is DSTest { - uint32 constant FEATURE_MASK_LISTING_FEE = 1 << 3; - uint32 constant FEATURE_MASK_FINDERS_FEE = 1 << 4; - uint32 constant FEATURE_MASK_ERC20_CURRENCY = 1 << 5; - uint32 constant FEATURE_MASK_TOKEN_GATE = 1 << 6; - uint32 constant FEATURE_MASK_START_TIME = 1 << 7; - uint32 constant FEATURE_MASK_RECIPIENT_OR_EXPIRY = 1 << 8; - - VM internal vm; - - function test_AuctionStorageMinimalInit() public { - StorageTestBaseMinimal dataStorage = new StorageTestBaseMinimal(); - dataStorage.newAuction(address(0x11), 21); - ReserveAuctionDataStorage.FullAuction memory auction = dataStorage.getFullAuction(address(0x11), 21); - assertEq(auction.seller, address(0x001), "seller wrong"); - assertEq(auction.reservePrice, 0.4 ether, "reserve price wrong"); - assertEq(auction.duration, 1000, "duration wrong"); - assertEq(auction.startTime, 0, "starttime wrong"); - assertEq(auction.features, 0, "features wrong"); - assertEq(auction.findersFeeBps, 0, "findersfeebps wrong"); - assertEq(auction.currency, address(0x0)); - assertEq(auction.ongoingAuction.firstBidTime, 0); - assertEq(auction.ongoingAuction.highestBidder, address(0x0)); - assertEq(auction.ongoingAuction.highestBid, 0); - assertEq(auction.listingFeeBps, 0, "listingfee wrong"); - assertEq(auction.listingFeeRecipient, address(0x0), "listingfee recipient wrong"); - assertEq(auction.tokenGateToken, address(0x0), "tokengate wrong"); - assertEq(auction.tokenGateMinAmount, 0, "tokengate wrong"); - assertEq(auction.expiry, 0, "expiry wrong"); - assertEq(auction.fundsRecipient, address(0), "funds recipient wrong"); - } - - function test_AuctionStorageInit() public { - StorageTestBaseFull dataStorage = new StorageTestBaseFull(); - dataStorage.newAuction(address(0x12), 21); - ReserveAuctionDataStorage.FullAuction memory auction = dataStorage.getFullAuction(address(0x12), 21); - assertEq(auction.seller, address(0x001), "seller wrong"); - assertEq(auction.reservePrice, 0.4 ether, "reserve price wrong"); - assertEq(auction.duration, 2 hours, "duration wrong"); - assertEq(auction.startTime, block.timestamp + 1 days, "starttime wrong"); - assertEq(auction.features, dataStorage.getExpectedActiveFeatures(), "features wrong"); - assertEq(auction.findersFeeBps, 2, "findersfeebps wrong"); - assertEq(auction.currency, address(0x002), "currency wrong"); - assertEq(auction.ongoingAuction.firstBidTime, 0); - assertEq(auction.ongoingAuction.highestBidder, address(0x0)); - assertEq(auction.ongoingAuction.highestBid, 0); - assertEq(auction.listingFeeBps, 1, "listingfee wrong"); - assertEq(auction.listingFeeRecipient, address(0x004), "listingfee recipient wrong"); - assertEq(auction.tokenGateToken, address(0x003), "tokengate wrong"); - assertEq(auction.tokenGateMinAmount, 0.1 ether, "tokengate wrong"); - assertEq(auction.expiry, uint96(block.timestamp) + 2 days, "expiry wrong"); - assertEq(auction.fundsRecipient, address(0x005), "funds recipient wrong"); - } -} diff --git a/contracts/test/modules/ReserveAuction/Omnibus/ReserveAuctionOmnibus.t.sol b/contracts/test/modules/ReserveAuction/Omnibus/ReserveAuctionOmnibus.t.sol deleted file mode 100644 index 79dda679..00000000 --- a/contracts/test/modules/ReserveAuction/Omnibus/ReserveAuctionOmnibus.t.sol +++ /dev/null @@ -1,1133 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -import {DSTest} from "ds-test/test.sol"; - -import {ReserveAuctionDataStorage, FEATURE_MASK_LISTING_FEE, FEATURE_MASK_FINDERS_FEE, FEATURE_MASK_ERC20_CURRENCY, FEATURE_MASK_TOKEN_GATE, FEATURE_MASK_START_TIME, FEATURE_MASK_RECIPIENT_OR_EXPIRY} from "../../../../modules/ReserveAuction/Omnibus/ReserveAuctionDataStorage.sol"; -import {ReserveAuctionOmnibus} from "../../../../modules/ReserveAuction/Omnibus/ReserveAuctionOmnibus.sol"; -import {IReserveAuctionOmnibus} from "../../../../modules/ReserveAuction/Omnibus/IReserveAuctionOmnibus.sol"; -import {Zorb} from "../../../utils/users/Zorb.sol"; -import {ZoraRegistrar} from "../../../utils/users/ZoraRegistrar.sol"; -import {ZoraModuleManager} from "../../../../ZoraModuleManager.sol"; -import {ZoraProtocolFeeSettings} from "../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol"; -import {ERC20TransferHelper} from "../../../../transferHelpers/ERC20TransferHelper.sol"; -import {ERC721TransferHelper} from "../../../../transferHelpers/ERC721TransferHelper.sol"; -import {RoyaltyEngine} from "../../../utils/modules/RoyaltyEngine.sol"; -import {TestERC20} from "../../../utils/tokens/TestERC20.sol"; -import {TestERC721} from "../../../utils/tokens/TestERC721.sol"; -import {WETH} from "../../../utils/tokens/WETH.sol"; -import {VM} from "../../../utils/VM.sol"; - -/// @title ReserveAuctionOmnibusTest -/// @notice Unit Tests for Reserve Auction Omnibus -contract ReserveAuctionOmnibusTest is DSTest { - VM internal vm; - - ZoraRegistrar internal registrar; - ZoraProtocolFeeSettings internal ZPFS; - ZoraModuleManager internal ZMM; - ERC20TransferHelper internal erc20TransferHelper; - ERC721TransferHelper internal erc721TransferHelper; - RoyaltyEngine internal royaltyEngine; - - ReserveAuctionOmnibus internal auctions; - TestERC20 internal erc20; - TestERC721 internal token; - WETH internal weth; - - Zorb internal seller; - Zorb internal sellerFundsRecipient; - Zorb internal operator; - Zorb internal finder; - Zorb internal royaltyRecipient; - Zorb internal bidder; - Zorb internal otherBidder; - - function setUp() public { - // Cheatcodes - vm = VM(HEVM_ADDRESS); - - // Deploy V3 - registrar = new ZoraRegistrar(); - ZPFS = new ZoraProtocolFeeSettings(); - ZMM = new ZoraModuleManager(address(registrar), address(ZPFS)); - erc20TransferHelper = new ERC20TransferHelper(address(ZMM)); - erc721TransferHelper = new ERC721TransferHelper(address(ZMM)); - - // Init V3 - registrar.init(ZMM); - ZPFS.init(address(ZMM), address(0)); - - // Create users - seller = new Zorb(address(ZMM)); - sellerFundsRecipient = new Zorb(address(ZMM)); - operator = new Zorb(address(ZMM)); - bidder = new Zorb(address(ZMM)); - otherBidder = new Zorb(address(ZMM)); - finder = new Zorb(address(ZMM)); - royaltyRecipient = new Zorb(address(ZMM)); - - // Deploy mocks - royaltyEngine = new RoyaltyEngine(address(royaltyRecipient)); - erc20 = new TestERC20(); - token = new TestERC721(); - weth = new WETH(); - - // Deploy Reserve Auction Finders ERC-20 - auctions = new ReserveAuctionOmnibus( - address(erc20TransferHelper), - address(erc721TransferHelper), - address(royaltyEngine), - address(ZPFS), - address(weth) - ); - registrar.registerModule(address(auctions)); - - // Set balances - vm.deal(address(seller), 100 ether); - vm.deal(address(bidder), 100 ether); - vm.deal(address(otherBidder), 100 ether); - - // Mint seller token - token.mint(address(seller), 0); - - // Mint bidder 2^96 ERC-20 tokens - erc20.mint(address(bidder), 2**96); - - // Bidder swap 50 ETH <> 50 WETH - vm.prank(address(bidder)); - weth.deposit{value: 50 ether}(); - - // otherBidder swap 50 ETH <> 50 WETH - vm.prank(address(otherBidder)); - weth.deposit{value: 50 ether}(); - - // Users approve ReserveAuction module - seller.setApprovalForModule(address(auctions), true); - bidder.setApprovalForModule(address(auctions), true); - otherBidder.setApprovalForModule(address(auctions), true); - - // Seller approve ERC721TransferHelper - vm.prank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), true); - - // Bidder approve ERC20TransferHelper for TestERC20 - vm.prank(address(bidder)); - erc20.approve(address(erc20TransferHelper), 2**96); - - // Bidder approve ERC20TransferHelper for WETH - vm.prank(address(bidder)); - weth.approve(address(erc20TransferHelper), 50 ether); - - // otherBidder approve ERC20TransferHelper - vm.prank(address(otherBidder)); - weth.approve(address(erc20TransferHelper), 50 ether); - } - - /// ------------ CREATE AUCTION ------------ /// - - function test_CreateAuction() public { - vm.prank(address(seller)); - - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - block.timestamp + 1 days, - 2 ether, - address(token), - 1 days, - 1, - 0, - address(sellerFundsRecipient), - uint96(block.timestamp + 3 days), - address(0x001), - 2, - 0, - address(erc20), - address(weth) - ) - ); - - ReserveAuctionDataStorage.FullAuction memory auction = auctions.getFullAuction(address(token), 0); - - require(auction.reservePrice == 1 ether); - require(auction.startTime == block.timestamp + 1 days); - require(auction.seller == address(seller)); - require(auction.expiry == block.timestamp + 3 days); - require(auction.currency == address(weth)); - require(auction.duration == 1 days); - require( - auction.features == - FEATURE_MASK_LISTING_FEE | - FEATURE_MASK_FINDERS_FEE | - FEATURE_MASK_ERC20_CURRENCY | - FEATURE_MASK_TOKEN_GATE | - FEATURE_MASK_START_TIME | - FEATURE_MASK_RECIPIENT_OR_EXPIRY - ); - require(auction.finder == address(0)); - require(auction.findersFeeBps == 1); - require(auction.fundsRecipient == address(sellerFundsRecipient)); - require(auction.ongoingAuction.firstBidTime == 0); - require(auction.ongoingAuction.highestBidder == address(0)); - require(auction.ongoingAuction.highestBid == 0); - require(auction.listingFeeRecipient == address(0x001)); - require(auction.listingFeeBps == 2); - require(auction.tokenGateToken == address(erc20)); - require(auction.tokenGateMinAmount == 2 ether); - } - - function test_CreateAuctionMinimal() public { - vm.prank(address(seller)); - auctions.createAuctionMinimal(address(token), 0, 1 ether, 1 days); - - ReserveAuctionDataStorage.FullAuction memory auction = auctions.getFullAuction(address(token), 0); - - require(auction.reservePrice == 1 ether); - require(auction.startTime == 0); - require(auction.seller == address(seller)); - require(auction.expiry == 0); - require(auction.currency == address(0)); - require(auction.duration == 1 days); - require(auction.features == 0); - require(auction.finder == address(0)); - require(auction.findersFeeBps == 0); - require(auction.fundsRecipient == address(0)); - require(auction.ongoingAuction.firstBidTime == 0); - require(auction.ongoingAuction.highestBidder == address(0)); - require(auction.ongoingAuction.highestBid == 0); - require(auction.listingFeeRecipient == address(0)); - require(auction.listingFeeBps == 0); - require(auction.tokenGateToken == address(0)); - require(auction.tokenGateMinAmount == 0 ether); - } - - function test_CreateAuctionAndCancelPrevious() public { - vm.prank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 1000, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - - vm.prank(address(seller)); - token.transferFrom(address(seller), address(sellerFundsRecipient), 0); - - sellerFundsRecipient.setApprovalForModule(address(auctions), true); - - vm.startPrank(address(sellerFundsRecipient)); - token.setApprovalForAll(address(erc721TransferHelper), true); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 12 ether, - 0, - 0, - address(token), - 5 days, - 1000, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.stopPrank(); - - ReserveAuctionDataStorage.FullAuction memory auction = auctions.getFullAuction(address(token), 0); - require(auction.seller == address(sellerFundsRecipient)); - require(auction.duration == 5 days); - require(auction.reservePrice == 12 ether); - } - - function testRevert_MustBeTokenOwnerOrOperator() public { - vm.expectRevert(abi.encodeWithSignature("NOT_TOKEN_OWNER_OR_OPERATOR()")); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 1000, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - } - - function testRevert_CreateAuctionModuleOrTransferHelperNotApproved() public { - vm.startPrank(address(seller)); - token.setApprovalForAll(address(erc721TransferHelper), false); - vm.expectRevert(abi.encodeWithSignature("TRANSFER_HELPER_NOT_APPROVED()")); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - block.timestamp + 1 days, - 2 ether, - address(token), - 1 days, - 1, - 0, - address(sellerFundsRecipient), - uint96(block.timestamp + 3 days), - address(0x001), - 2, - 0, - address(erc20), - address(weth) - ) - ); - - token.setApprovalForAll(address(erc721TransferHelper), true); - seller.setApprovalForModule(address(auctions), false); - vm.expectRevert(abi.encodeWithSignature("MODULE_NOT_APPROVED()")); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - block.timestamp + 1 days, - 2 ether, - address(token), - 1 days, - 1, - 0, - address(sellerFundsRecipient), - uint96(block.timestamp + 3 days), - address(0x001), - 2, - 0, - address(erc20), - address(weth) - ) - ); - vm.stopPrank(); - } - - function testRevert_FindersFeePlusListingFeeCannotExceed10000() public { - vm.prank(address(seller)); - vm.expectRevert(abi.encodeWithSignature("INVALID_FEES()")); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 5000, - 0, - address(sellerFundsRecipient), - 0, - address(sellerFundsRecipient), - 5001, - 0, - address(0), - address(weth) - ) - ); - } - - function testRevert_TimeBufferMustBeValid() public { - vm.startPrank(address(seller)); - vm.expectRevert(abi.encodeWithSignature("INVALID_TIME_BUFFER()")); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 3 hours, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.expectRevert(abi.encodeWithSignature("INVALID_TIME_BUFFER()")); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 1 seconds, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.stopPrank(); - } - - function testRevert_PercentIncrementMustBeValid() public { - vm.prank(address(seller)); - vm.expectRevert(abi.encodeWithSignature("INVALID_PERCENT_INCREMENT()")); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 51, - address(0), - address(weth) - ) - ); - } - - /// ------------ SET AUCTION RESERVE PRICE ------------ /// - - function test_SetReservePrice() public { - vm.startPrank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - auctions.setAuctionReservePrice(address(token), 0, 5 ether); - vm.stopPrank(); - ReserveAuctionDataStorage.FullAuction memory auction = auctions.getFullAuction(address(token), 0); - require(auction.reservePrice == 5 ether); - } - - function test_SetReservePriceOperator() public { - vm.startPrank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - token.setApprovalForAll(address(sellerFundsRecipient), true); - vm.stopPrank(); - vm.prank(address(sellerFundsRecipient)); - auctions.setAuctionReservePrice(address(token), 0, 5 ether); - ReserveAuctionDataStorage.FullAuction memory auction = auctions.getFullAuction(address(token), 0); - require(auction.reservePrice == 5 ether); - } - - function testRevert_UpdateMustBeTokenOwnerOrOperator() public { - vm.prank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.expectRevert(abi.encodeWithSignature("NOT_TOKEN_OWNER_OR_OPERATOR()")); - auctions.setAuctionReservePrice(address(token), 0, 5 ether); - } - - function testRevert_CannotUpdateAuctionDoesNotExist() public { - ReserveAuctionDataStorage.FullAuction memory auction = auctions.getFullAuction(address(token), 0); - assertEq(auction.seller, address(0)); - vm.prank(token.ownerOf(0)); - vm.expectRevert(abi.encodeWithSignature("AUCTION_DOES_NOT_EXIST()")); - auctions.setAuctionReservePrice(address(token), 0, 5 ether); - } - - function testRevert_CannotUpdateActiveAuction() public { - vm.prank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 5 ether, address(finder)); - vm.prank(address(seller)); - vm.expectRevert(abi.encodeWithSignature("AUCTION_STARTED()")); - auctions.setAuctionReservePrice(address(token), 0, 20 ether); - } - - /// ------------ CANCEL AUCTION ------------ /// - - function test_CancelAuction() public { - vm.startPrank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.warp(1 minutes); - auctions.cancelAuction(address(token), 0); - vm.stopPrank(); - ReserveAuctionDataStorage.FullAuction memory auction = auctions.getFullAuction(address(token), 0); - require(auction.seller == address(0)); - } - - function testRevert_OnlySellerOrOperatorCanCancelValidAuction() public { - vm.prank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.expectRevert(abi.encodeWithSignature("NOT_TOKEN_OWNER_OR_OPERATOR()")); - auctions.cancelAuction(address(token), 0); - } - - function testRevert_PublicCanCancelInalidAuction() public { - vm.startPrank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - token.safeTransferFrom(address(seller), address(sellerFundsRecipient), 0); - vm.stopPrank(); - auctions.cancelAuction(address(token), 0); - } - - function testRevert_CannotCancelActiveAuction() public { - vm.prank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - vm.prank(address(seller)); - vm.expectRevert(abi.encodeWithSignature("AUCTION_STARTED()")); - auctions.cancelAuction(address(token), 0); - } - - /// ------------ CREATE BID ------------ /// - - function test_CreateFirstBid() public { - vm.prank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.prank(address(bidder)); - vm.warp(1 hours); - - auctions.createBid(address(token), 0, 1 ether, address(finder)); - ReserveAuctionDataStorage.FullAuction memory auction = auctions.getFullAuction(address(token), 0); - assertEq(auction.ongoingAuction.highestBid, 1 ether); - assertEq(auction.ongoingAuction.highestBidder, address(bidder)); - assertEq(auction.ongoingAuction.firstBidTime, 1 hours); - } - - function test_RefundPreviousBidder() public { - vm.prank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - uint256 beforeBalance = weth.balanceOf(address(bidder)); - vm.prank(address(otherBidder)); - auctions.createBid(address(token), 0, 2 ether, address(finder)); - uint256 afterBalance = weth.balanceOf(address(bidder)); - require(afterBalance - beforeBalance == 1 ether); - } - - function test_TransferNFTIntoEscrow() public { - vm.prank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - require(token.ownerOf(0) == address(auctions)); - } - - function test_ExtendAuction() public { - vm.prank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 hours, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.warp(5 minutes); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - vm.warp(55 minutes); - vm.prank(address(otherBidder)); - auctions.createBid(address(token), 0, 2 ether, address(finder)); - ReserveAuctionDataStorage.FullAuction memory auction = auctions.getFullAuction(address(token), 0); - require(auction.duration == 1 hours + 5 minutes); - } - - function test_ExtendAuctionWithCustomBuffer() public { - vm.prank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 3 hours, - 0, - 1 hours, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.warp(10 minutes); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - vm.warp(2 hours + 20 minutes); - vm.prank(address(otherBidder)); - auctions.createBid(address(token), 0, 2 ether, address(finder)); - ReserveAuctionDataStorage.FullAuction memory auction = auctions.getFullAuction(address(token), 0); - assertEq(auction.duration, 3 hours + 10 minutes); - } - - function testRevert_MustApproveModule() public { - vm.startPrank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 hours, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - seller.setApprovalForModule(address(auctions), false); - vm.stopPrank(); - - vm.prank(address(bidder)); - vm.expectRevert("module has not been approved by user"); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - } - - function testRevert_SellerMustApproveERC721TransferHelper() public { - vm.startPrank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 hours, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - token.setApprovalForAll(address(erc721TransferHelper), false); - vm.stopPrank(); - - vm.prank(address(bidder)); - vm.expectRevert("ERC721: transfer caller is not owner nor approved"); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - } - - function testRevert_InvalidTransferBeforeFirstBid() public { - vm.prank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 hours, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.prank(address(seller)); - token.transferFrom(address(seller), address(otherBidder), 0); - vm.prank(address(bidder)); - vm.expectRevert("ERC721: transfer caller is not owner nor approved"); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - } - - function testRevert_CannotBidOnExpiredAuction() public { - vm.prank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 10 hours, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - vm.warp(12 hours); - vm.prank(address(otherBidder)); - vm.expectRevert(abi.encodeWithSignature("AUCTION_OVER()")); - auctions.createBid(address(token), 0, 2 ether, address(finder)); - } - - function testRevert_CannotBidOnAuctionNotStarted() public { - vm.prank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - block.timestamp + 1 days, - 0, - address(token), - 10 hours, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.prank(address(bidder)); - vm.expectRevert(abi.encodeWithSignature("AUCTION_NOT_STARTED()")); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - } - - function testRevert_CannotBidOnNonExistentAuction() public { - vm.expectRevert(abi.encodeWithSignature("AUCTION_DOES_NOT_EXIST()")); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - } - - function testRevert_BidMustMeetReservePrice() public { - vm.prank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.prank(address(bidder)); - vm.expectRevert(abi.encodeWithSignature("RESERVE_PRICE_NOT_MET()")); - auctions.createBid(address(token), 0, 0.5 ether, address(finder)); - } - - function testRevert_BidMustBeDefaultPercentGreaterThanPrevious() public { - vm.prank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - vm.warp(1 hours + 1 minutes); - vm.startPrank(address(otherBidder)); - vm.expectRevert(abi.encodeWithSignature("MINIMUM_BID_NOT_MET()")); - auctions.createBid(address(token), 0, 1.01 ether, address(finder)); - auctions.createBid(address(token), 0, 1.10 ether, address(finder)); - vm.stopPrank(); - } - - function testRevert_BidMustBeCustomPercentGreaterThanPrevious() public { - vm.prank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 15, - address(0), - address(weth) - ) - ); - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - vm.warp(1 hours + 1 minutes); - vm.startPrank(address(otherBidder)); - vm.expectRevert(abi.encodeWithSignature("MINIMUM_BID_NOT_MET()")); - auctions.createBid(address(token), 0, 1.10 ether, address(finder)); - auctions.createBid(address(token), 0, 1.15 ether, address(finder)); - vm.stopPrank(); - } - - /// ------------ SETTLE AUCTION ------------ /// - - function test_SettleAuction() public { - vm.prank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - vm.warp(10 hours); - vm.prank(address(otherBidder)); - auctions.createBid(address(token), 0, 5 ether, address(finder)); - vm.warp(1 days + 1 hours); - auctions.settleAuction(address(token), 0); - require(token.ownerOf(0) == address(otherBidder)); - } - - function testRevert_AuctionNotStarted() public { - vm.prank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.expectRevert(abi.encodeWithSignature("AUCTION_NOT_STARTED()")); - auctions.settleAuction(address(token), 0); - } - - function testRevert_AuctionNotOver() public { - vm.prank(address(seller)); - auctions.createAuction( - IReserveAuctionOmnibus.CreateAuctionParameters( - 0, - 1 ether, - 0, - 0, - address(token), - 1 days, - 0, - 0, - address(sellerFundsRecipient), - 0, - address(0), - 0, - 0, - address(0), - address(weth) - ) - ); - vm.warp(1 hours); - vm.prank(address(bidder)); - auctions.createBid(address(token), 0, 1 ether, address(finder)); - vm.warp(10 hours); - vm.expectRevert(abi.encodeWithSignature("AUCTION_NOT_OVER()")); - auctions.settleAuction(address(token), 0); - } -} diff --git a/contracts/transferHelpers/ERC20TransferHelper.sol b/contracts/transferHelpers/ERC20TransferHelper.sol index 36142bff..9e28ceaa 100644 --- a/contracts/transferHelpers/ERC20TransferHelper.sol +++ b/contracts/transferHelpers/ERC20TransferHelper.sol @@ -4,6 +4,7 @@ pragma solidity 0.8.10; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {BaseTransferHelper} from "./BaseTransferHelper.sol"; +import {ITurnstile} from "../csr/ITurnstile.sol"; /// @title ERC-20 Transfer Helper /// @author tbtstl @@ -11,7 +12,9 @@ import {BaseTransferHelper} from "./BaseTransferHelper.sol"; contract ERC20TransferHelper is BaseTransferHelper { using SafeERC20 for IERC20; - constructor(address _approvalsManager) BaseTransferHelper(_approvalsManager) {} + constructor(address _approvalsManager) BaseTransferHelper(_approvalsManager) { + ITurnstile(0xEcf044C5B4b867CFda001101c617eCd347095B44).assign(22); //sets Canto CSR parameters + } function safeTransferFrom( address _token, diff --git a/contracts/transferHelpers/ERC721TransferHelper.sol b/contracts/transferHelpers/ERC721TransferHelper.sol index f19a4a03..7e007d96 100644 --- a/contracts/transferHelpers/ERC721TransferHelper.sol +++ b/contracts/transferHelpers/ERC721TransferHelper.sol @@ -3,12 +3,15 @@ pragma solidity 0.8.10; import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import {BaseTransferHelper} from "./BaseTransferHelper.sol"; +import {ITurnstile} from "../csr/ITurnstile.sol"; /// @title ERC-721 Transfer Helper /// @author tbtstl /// @notice This contract provides modules the ability to transfer ZORA user ERC-721s with their permission contract ERC721TransferHelper is BaseTransferHelper { - constructor(address _approvalsManager) BaseTransferHelper(_approvalsManager) {} + constructor(address _approvalsManager) BaseTransferHelper(_approvalsManager) { + ITurnstile(0xEcf044C5B4b867CFda001101c617eCd347095B44).assign(22); //sets Canto CSR parameters + } function safeTransferFrom( address _token, From b62c23f60520b03e984422feceb574ecf30d232d Mon Sep 17 00:00:00 2001 From: Rohan2407 Date: Wed, 17 May 2023 10:02:30 +0530 Subject: [PATCH 4/4] added proxyFactory and mockContracts --- contracts/mockContracts/DionysusNFT.sol | 20 +++++++ contracts/mockContracts/WETH.sol | 72 +++++++++++++++++++++++++ contracts/proxyFactory/ProxyFactory.sol | 30 +++++++++++ 3 files changed, 122 insertions(+) create mode 100644 contracts/mockContracts/DionysusNFT.sol create mode 100644 contracts/mockContracts/WETH.sol create mode 100644 contracts/proxyFactory/ProxyFactory.sol diff --git a/contracts/mockContracts/DionysusNFT.sol b/contracts/mockContracts/DionysusNFT.sol new file mode 100644 index 00000000..da39e685 --- /dev/null +++ b/contracts/mockContracts/DionysusNFT.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.10; + +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; + +contract DionysusNFT is ERC721URIStorage, Ownable { + uint256 private currentTokenId = 0; + + constructor() ERC721("DionysusNFT", "d-666") {} + + function mintNFT(address recipient, string memory tokenURI) public onlyOwner returns (uint256) { + currentTokenId++; + + _mint(recipient, currentTokenId); + _setTokenURI(currentTokenId, tokenURI); + + return currentTokenId; + } +} diff --git a/contracts/mockContracts/WETH.sol b/contracts/mockContracts/WETH.sol new file mode 100644 index 00000000..652b8551 --- /dev/null +++ b/contracts/mockContracts/WETH.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.10; + +/// @title WETH +/// @notice FOR TEST PURPOSES ONLY. Source: https://github.com/gnosis/canonical-weth/blob/0dd1ea3e295eef916d0c6223ec63141137d22d67/contracts/WETH9.sol +contract WETH { + string public name = "Wrapped Ether"; + string public symbol = "WETH"; + uint8 public decimals = 18; + + event Approval(address indexed src, address indexed guy, uint256 wad); + event Transfer(address indexed src, address indexed dst, uint256 wad); + event Deposit(address indexed dst, uint256 wad); + event Withdrawal(address indexed src, uint256 wad); + + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) public allowance; + + fallback() external payable { + deposit(); + } + + receive() external payable { + deposit(); + } + + function deposit() public payable { + balanceOf[msg.sender] += msg.value; + emit Deposit(msg.sender, msg.value); + } + + function withdraw(uint256 wad) public { + require(balanceOf[msg.sender] >= wad); + balanceOf[msg.sender] -= wad; + payable(msg.sender).transfer(wad); + emit Withdrawal(msg.sender, wad); + } + + function totalSupply() public view returns (uint256) { + return address(this).balance; + } + + function approve(address guy, uint256 wad) public returns (bool) { + allowance[msg.sender][guy] = wad; + emit Approval(msg.sender, guy, wad); + return true; + } + + function transfer(address dst, uint256 wad) public returns (bool) { + return transferFrom(msg.sender, dst, wad); + } + + function transferFrom( + address src, + address dst, + uint256 wad + ) public returns (bool) { + require(balanceOf[src] >= wad); + + if (src != msg.sender && allowance[src][msg.sender] != type(uint128).max) { + require(allowance[src][msg.sender] >= wad); + allowance[src][msg.sender] -= wad; + } + + balanceOf[src] -= wad; + balanceOf[dst] += wad; + + emit Transfer(src, dst, wad); + + return true; + } +} diff --git a/contracts/proxyFactory/ProxyFactory.sol b/contracts/proxyFactory/ProxyFactory.sol new file mode 100644 index 00000000..6c5e7e06 --- /dev/null +++ b/contracts/proxyFactory/ProxyFactory.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.10; + +import "@openzeppelin/contracts/proxy/Clones.sol"; + +contract ProxyFactory { + address public immutable implementation; + + event ProxyCreated(address proxy); + + constructor(address _implementation) { + implementation = _implementation; + } + + function createProxy() public { + address clone = Clones.clone(implementation); + + emit ProxyCreated(clone); + } + + function createProxyAndCall(bytes calldata data) public { + address clone = Clones.clone(implementation); + + (bool success, ) = clone.call(data); + + require(success, "ProxyFactory: Failed to call function on clone"); + + emit ProxyCreated(clone); + } +}