Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[UPD] GAS optimisations / DRY #1268

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion contracts/helpers/SeaportRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ contract SeaportRouter is SeaportRouterInterface, ReentrancyGuard {
}

// Iterate through the provided Seaport contracts.
for (uint256 i = 0; i < params.seaportContracts.length; ) {
for (uint256 i = 0; i < seaportContractsLength; ) {
// Ensure the provided Seaport contract is allowed.
_assertSeaportAllowed(params.seaportContracts[i]);

Expand Down
3 changes: 2 additions & 1 deletion contracts/helpers/navigator/SeaportNavigator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ contract SeaportNavigator is SeaportNavigatorInterface {
.from(request)
.withEmptyResponse();

for (uint256 i; i < helpers.length; i++) {
uint256 helpersLength = helpers.length;
for (uint256 i; i < helpersLength; i++) {
context = helpers[i].prepare(context);
}

Expand Down
22 changes: 11 additions & 11 deletions contracts/helpers/navigator/lib/CriteriaHelperLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ library CriteriaHelperLib {
uint256 idx;
bool found;
bytes32[] memory idHashes = toSortedHashes(tokenIds);
for (; idx < idHashes.length; idx++) {
uint256 idHashesLength = idHashes.length;
for (; idx < idHashesLength; idx++) {
if (idHashes[idx] == idHash) {
found = true;
break;
Expand All @@ -73,12 +74,12 @@ library CriteriaHelperLib {
uint256[] memory tokenIds
) internal pure returns (uint256[] memory sortedIds) {
// Instantiate a new array of HashAndIntTuple structs.
uint256 tokenIdsLength = tokenIds.length;
HashAndIntTuple[] memory toSort = new HashAndIntTuple[](
tokenIds.length
);

// Populate the array of HashAndIntTuple structs.
for (uint256 i = 0; i < tokenIds.length; i++) {
tokenIdsLength
);
// Populate the array of HashAndIntTuple structs.
for (uint256 i = 0; i < tokenIdsLength; i++) {
toSort[i] = HashAndIntTuple(
tokenIds[i],
keccak256(abi.encode(tokenIds[i]))
Expand All @@ -87,10 +88,9 @@ library CriteriaHelperLib {

// Sort the array of HashAndIntTuple structs.
_quickSort(toSort, 0, int256(toSort.length - 1));

// Populate the sortedIds array with the sorted token ids.
sortedIds = new uint256[](tokenIds.length);
for (uint256 i = 0; i < tokenIds.length; i++) {
sortedIds = new uint256[](tokenIdsLength);
for (uint256 i = 0; i < tokenIdsLength; i++) {
sortedIds[i] = toSort[i].num;
}
}
Expand All @@ -107,9 +107,9 @@ library CriteriaHelperLib {

// Sort the token ids by their hashes.
uint256[] memory ids = sortByHash(tokenIds);

// Hash each token id and store it in the hashes array.
for (uint256 i; i < ids.length; ++i) {
uint256 idsLength = ids.length;
for (uint256 i; i < idsLength; ++i) {
hashes[i] = keccak256(abi.encode(ids[i]));
}
}
Expand Down
135 changes: 52 additions & 83 deletions contracts/helpers/navigator/lib/HelperItemLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,7 @@ library HelperItemLib {
) internal pure returns (ItemType) {
ItemType itemType = item.itemType;
if (hasCriteria(item)) {
if (
itemType == ItemType.ERC721 ||
itemType == ItemType.ERC721_WITH_CRITERIA
) {
return ItemType.ERC721_WITH_CRITERIA;
} else if (
itemType == ItemType.ERC1155 ||
itemType == ItemType.ERC1155_WITH_CRITERIA
) {
return ItemType.ERC1155_WITH_CRITERIA;
} else {
revert UnknownItemType();
}
return _normalizeType(itemType);
} else {
return itemType;
}
Expand All @@ -73,19 +61,7 @@ library HelperItemLib {
) internal pure returns (ItemType) {
ItemType itemType = item.itemType;
if (hasCriteria(item)) {
if (
itemType == ItemType.ERC721 ||
itemType == ItemType.ERC721_WITH_CRITERIA
) {
return ItemType.ERC721_WITH_CRITERIA;
} else if (
itemType == ItemType.ERC1155 ||
itemType == ItemType.ERC1155_WITH_CRITERIA
) {
return ItemType.ERC1155_WITH_CRITERIA;
} else {
revert UnknownItemType();
}
return _normalizeType(itemType);
} else {
return itemType;
}
Expand All @@ -108,86 +84,79 @@ library HelperItemLib {
}

function validate(NavigatorOfferItem memory item) internal pure {
ItemType itemType = item.itemType;
_validateItem(
item.itemType,
item.candidateIdentifiers.length,
item.identifier,
item.candidateIdentifiers,
hasCriteria(item)
);
}

function validate(NavigatorConsiderationItem memory item) internal pure {
_validateItem(
item.itemType,
item.candidateIdentifiers.length,
item.identifier,
item.candidateIdentifiers,
hasCriteria(item)
);
}

function _normalizeType(ItemType itemType) private pure returns (ItemType) {
if (
itemType == ItemType.ERC721 ||
itemType == ItemType.ERC721_WITH_CRITERIA
) {
return ItemType.ERC721_WITH_CRITERIA;
} else if (
itemType == ItemType.ERC1155 ||
itemType == ItemType.ERC1155_WITH_CRITERIA
) {
return ItemType.ERC1155_WITH_CRITERIA;
} else {
revert UnknownItemType();
}
}

// Shared function to validate Navigator items
function _validateItem(
ItemType itemType,
uint256 itemCandidateIdentifiersLength,
uint256 identifier,
uint256[] memory candidateIdentifiers,
bool _hasCriteria
) private pure {
// If the item has criteria, the item type must be ERC721 or ERC1155.
if (itemType == ItemType.ERC20 || itemType == ItemType.NATIVE) {
if (hasCriteria(item)) {
if (_hasCriteria) {
revert InvalidItemTypeForCandidateIdentifiers();
} else {
return;
}
}

// If the item has no candidate identifiers, the item identifier must be
// non-zero.
//
// NOTE: This is only called after `item.hasCriteria()` checks
// which ensure that `item.candidateIdentifiers.length > 0` but if it
// were used in other contexts, this would prohibit the use of
// legitimate 0 identifiers.
if (item.candidateIdentifiers.length == 0 && item.identifier == 0) {
revert InvalidIdentifier(
item.identifier,
item.candidateIdentifiers
);
}

// If the item has candidate identifiers, the item identifier must be
// zero or wildcard for one of the candidates.
if (item.candidateIdentifiers.length > 0) {
bool identifierFound;
for (uint256 i; i < item.candidateIdentifiers.length; i++) {
if (item.candidateIdentifiers[i] == item.identifier) {
identifierFound = true;
break;
}
}
if (!identifierFound && item.identifier != 0) {
revert InvalidIdentifier(
item.identifier,
item.candidateIdentifiers
);
}
if (itemCandidateIdentifiersLength == 0 && identifier == 0) {
revert InvalidIdentifier(identifier, candidateIdentifiers);
}
}

function validate(NavigatorConsiderationItem memory item) internal pure {
ItemType itemType = item.itemType;

// If the item has criteria, the item type must be ERC721 or ERC1155.
if (itemType == ItemType.ERC20 || itemType == ItemType.NATIVE) {
if (hasCriteria(item)) {
revert InvalidItemTypeForCandidateIdentifiers();
} else {
return;
}
}

// If the item has no candidate identifiers, the item identifier must be
// non-zero.
if (item.candidateIdentifiers.length == 0 && item.identifier == 0) {
revert InvalidIdentifier(
item.identifier,
item.candidateIdentifiers
);
}

// If the item has candidate identifiers, the item identifier must be
// zero or wildcard for one of the candidates.
if (hasCriteria(item)) {
if (_hasCriteria) {
bool identifierFound;
for (uint256 i; i < item.candidateIdentifiers.length; i++) {
if (item.candidateIdentifiers[i] == item.identifier) {
for (uint256 i; i < itemCandidateIdentifiersLength; i++) {
if (candidateIdentifiers[i] == identifier) {
identifierFound = true;
break;
}
}
if (!identifierFound && item.identifier != 0) {
revert InvalidIdentifier(
item.identifier,
item.candidateIdentifiers
);
if (!identifierFound && identifier != 0) {
revert InvalidIdentifier(identifier, candidateIdentifiers);
}
}
}
Expand Down
16 changes: 8 additions & 8 deletions contracts/helpers/navigator/lib/MerkleLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ library MerkleLib {
) internal pure returns (bool) {
// Proof length must be less than max array size.
bytes32 rollingHash = valueToProve;
uint256 length = proof.length;
uint256 proofLength = proof.length;

// Loop through each proof element to compute the rolling hash.
unchecked {
for (uint i = 0; i < length; ++i) {
for (uint i = 0; i < proofLength; ++i) {
rollingHash = hashLeafPairs(rollingHash, proof[i]);
}
}
Expand Down Expand Up @@ -136,19 +136,19 @@ library MerkleLib {
// Underflow is not possible as lowest possible value for data/result index is 1
// overflow should be safe as length is / 2 always.
unchecked {
uint256 length = data.length;
if (length & 0x1 == 1) {
result = new bytes32[](length / 2 + 1);
uint256 dataLength = data.length;
if (dataLength & 0x1 == 1) {
result = new bytes32[](dataLength / 2 + 1);
result[result.length - 1] = hashLeafPairs(
data[length - 1],
data[dataLength - 1],
bytes32(0)
);
} else {
result = new bytes32[](length / 2);
result = new bytes32[](dataLength / 2);
}
// pos is upper bounded by data.length / 2, so safe even if array is at max size
uint256 pos = 0;
for (uint256 i = 0; i < length - 1; i += 2) {
for (uint256 i = 0; i < dataLength - 1; i += 2) {
result[pos] = hashLeafPairs(data[i], data[i + 1]);
++pos;
}
Expand Down
Loading