Skip to content
This repository has been archived by the owner on Dec 23, 2024. It is now read-only.

Commit

Permalink
offers omnibus (#174)
Browse files Browse the repository at this point in the history
  • Loading branch information
jgeary authored Oct 28, 2022
1 parent e260bc2 commit d111220
Show file tree
Hide file tree
Showing 5 changed files with 1,077 additions and 0 deletions.
81 changes: 81 additions & 0 deletions contracts/modules/Offers/Omnibus/IOffersOmnibus.sol
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);
}
119 changes: 119 additions & 0 deletions contracts/modules/Offers/Omnibus/OffersDataStorage.sol
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;
}
}
Loading

0 comments on commit d111220

Please sign in to comment.