Skip to content

Commit

Permalink
feat(fractions): added strategy and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bitbeckers committed Nov 23, 2023
1 parent 9657f17 commit a8f0300
Show file tree
Hide file tree
Showing 13 changed files with 972 additions and 19 deletions.
2 changes: 1 addition & 1 deletion contracts/src/marketplace/ExecutionManager.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
pragma solidity ^0.8.17;

// Libraries
import {OrderStructs} from "./libraries/OrderStructs.sol";
Expand Down
31 changes: 23 additions & 8 deletions contracts/src/marketplace/LooksRareProtocol.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
// Direct dependencies
import {TransferSelectorNFT} from "./TransferSelectorNFT.sol";
import {BatchOrderTypehashRegistry} from "./BatchOrderTypehashRegistry.sol";
import {StrategyHypercertFractionOffer} from "./executionStrategies/StrategyHypercertFractionOffer.sol";

// Constants
import {MAX_CALLDATA_PROOF_LENGTH, ONE_HUNDRED_PERCENT_IN_BP} from "./constants/NumericConstants.sol";
Expand Down Expand Up @@ -442,14 +443,28 @@ contract LooksRareProtocol is
_transferToAskRecipientAndCreatorIfAny(recipients, feeAmounts, makerAsk.currency, sender);

// Maker action goes second
_transferNFT(
makerAsk.collection,
makerAsk.collectionType,
signer,
takerBid.recipient == address(0) ? sender : takerBid.recipient,
itemIds,
amounts
);
if (
strategyInfo[makerAsk.strategyId].selector
== StrategyHypercertFractionOffer.executeHypercertFractionStrategyWithTakerBid.selector
) {
_splitNFT(
makerAsk.collection,
makerAsk.collectionType,
signer,
takerBid.recipient == address(0) ? sender : takerBid.recipient,
itemIds,
amounts
);
} else {
_transferNFT(
makerAsk.collection,
makerAsk.collectionType,
signer,
takerBid.recipient == address(0) ? sender : takerBid.recipient,
itemIds,
amounts
);
}

emit TakerBid(
NonceInvalidationParameters({
Expand Down
64 changes: 62 additions & 2 deletions contracts/src/marketplace/TransferManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ import {OwnableTwoSteps} from "@looksrare/contracts-libs/contracts/OwnableTwoSte
import {LowLevelERC721Transfer} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelERC721Transfer.sol";
import {LowLevelERC1155Transfer} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelERC1155Transfer.sol";

// Hypercert low-level callers
import {LowLevelHypercertCaller} from "./libraries/LowLevelHypercertCaller.sol";

// Interfaces and errors
import {ITransferManager} from "./interfaces/ITransferManager.sol";
import {AmountInvalid, LengthsInvalid} from "./errors/SharedErrors.sol";
import {IHypercertToken} from "../protocol/interfaces/IHypercertToken.sol";

// Libraries
import {OrderStructs} from "./libraries/OrderStructs.sol";
Expand All @@ -28,8 +32,13 @@ import {CollectionType} from "./enums/CollectionType.sol";
* to verify if the recipient is a contract as it requires verifying the receiver interface is valid.
* @author LooksRare protocol team (👀,💎)
*/
// TODO Needs to be updated to split a fraction and transfer the new fraction to the bidder
contract TransferManager is ITransferManager, LowLevelERC721Transfer, LowLevelERC1155Transfer, OwnableTwoSteps {
contract TransferManager is
ITransferManager,
LowLevelERC721Transfer,
LowLevelERC1155Transfer,
LowLevelHypercertCaller,
OwnableTwoSteps
{
/**
* @notice This returns whether the user has approved the operator address.
* The first address is the user and the second address is the operator (e.g. LooksRareProtocol).
Expand Down Expand Up @@ -166,6 +175,57 @@ contract TransferManager is ITransferManager, LowLevelERC721Transfer, LowLevelER
}
}

/**
* @notice This function transfers items for a single Hypercert.
* @param collection Collection address
* @param from Sender address
* @param to Recipient address
* @param itemIds Array of itemIds
* @param amounts Array of amounts
* @dev It does not allow batch transferring if from = msg.sender since native function should be used.
*/
function splitItemsHypercert(
address collection,
address from,
address to,
uint256[] calldata itemIds,
uint256[] calldata amounts
) external {
IHypercertToken hypercert = IHypercertToken(collection);
uint256 length = itemIds.length;

if (length == 0 || amounts.length != length) {
revert LengthsInvalid();
}

_isOperatorValidForTransfer(from, msg.sender);

if (length == 1) {
if (amounts[0] == 0) {
revert AmountInvalid();
}
uint256[] memory newAmounts = new uint256[](2);
newAmounts[0] = hypercert.unitsOf(itemIds[0]) - amounts[0];
newAmounts[1] = amounts[0];
_executeHypercertSplitFraction(collection, from, to, itemIds[0], newAmounts);
} else {
for (uint256 i; i < length;) {
if (amounts[i] == 0) {
revert AmountInvalid();
}

uint256[] memory newAmounts = new uint256[](2);
newAmounts[0] = hypercert.unitsOf(itemIds[0]) - amounts[0];
newAmounts[1] = amounts[0];
_executeHypercertSplitFraction(collection, from, to, itemIds[0], newAmounts);

unchecked {
++i;
}
}
}
}

/**
* @notice This function transfers items for a single Hyperboard.
* @param collection Collection address
Expand Down
26 changes: 25 additions & 1 deletion contracts/src/marketplace/TransferSelectorNFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {CollectionType} from "./enums/CollectionType.sol";
/**
* @title TransferSelectorNFT
* @notice This contract handles the logic for transferring non-fungible items.
* @author LooksRare protocol team (👀,💎)
* @author LooksRare protocol team (👀,💎); bitbeckers;
*/
contract TransferSelectorNFT is ExecutionManager, PackableReentrancyGuard {
error UnsupportedCollectionType();
Expand Down Expand Up @@ -64,4 +64,28 @@ contract TransferSelectorNFT is ExecutionManager, PackableReentrancyGuard {
revert UnsupportedCollectionType();
}
}

/**
* @notice This function is internal and used to transfer non-fungible tokens.
* @param collection Collection address
* @param collectionType Collection type (e.g. 0 = ERC721, 1 = ERC1155)
* @param sender Sender address
* @param recipient Recipient address
* @param itemIds Array of itemIds
* @param amounts Array of amounts
*/
function _splitNFT(
address collection,
CollectionType collectionType,
address sender,
address recipient,
uint256[] memory itemIds,
uint256[] memory amounts
) internal {
if (collectionType == CollectionType.Hypercert) {
transferManager.splitItemsHypercert(collection, sender, recipient, itemIds, amounts);
} else if (collectionType == CollectionType.Hyperboard) {
revert UnsupportedCollectionType();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ import {BaseStrategy, IStrategy} from "./BaseStrategy.sol";
* @notice This contract offers execution strategies for users to create maker bid offers for items in a collection.
* There are two available functions:
* 1. executeCollectionStrategyWithTakerAsk --> it applies to all itemIds in a collection
* 2. executeCollectionStrategyWithTakerAskWithProof --> it allows adding merkle proof criteria.
* 2. executeCollectionStrategyWithTakerAskWithProof --> it allows adding merkle proof criteria for tokenIds.
* 2. executeCollectionStrategyWithTakerAskWithAllowlist --> it allows adding merkle proof criteria for
* accounts.
* @notice The bidder can only bid on 1 item id at a time.
* 1. If ERC721, the amount must be 1.
* 2. If ERC1155, the amount can be greater than 1.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
pragma solidity ^0.8.17;

// Libraries
import {OrderStructs} from "../libraries/OrderStructs.sol";
Expand Down
Loading

0 comments on commit a8f0300

Please sign in to comment.