This repository has been archived by the owner on Dec 23, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 70
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
1,077 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
// SPDX-License-Identifier: GPL-3.0 | ||
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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
// SPDX-License-Identifier: GPL-3.0 | ||
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; | ||
} | ||
} |
Oops, something went wrong.