Skip to content

Commit

Permalink
Merge branch 'main' into integration-royalty-registry
Browse files Browse the repository at this point in the history
  • Loading branch information
zajck committed Dec 8, 2023
2 parents f7bf217 + ad6761e commit 179efde
Show file tree
Hide file tree
Showing 5 changed files with 490 additions and 18 deletions.
10 changes: 5 additions & 5 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ updates:
groups:
# Group only dev dependencies updates. Production dependencies should have a separate PR per update.
# Exclude major version updates from the dev dependencies group. Major version updates should have a separate PR per update.
- dev-dependencies:
dependency-type: "development"
update-types:
- "minor"
- "patch"
dev-dependencies:
dependency-type: "development"
update-types:
- "minor"
- "patch"
23 changes: 21 additions & 2 deletions contracts/protocol/bases/SellerBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ contract SellerBase is ProtocolBase, IBosonAccountEvents {
RoyaltyRecipient[] storage royaltyRecipients = lookups.royaltyRecipientsBySeller[sellerId];
RoyaltyRecipient storage defaultRoyaltyRecipient = royaltyRecipients.push();
// We don't store the defaultRoyaltyRecipient.wallet, since it's always the trasury
// We don't store the defaultRoyaltyRecipient.externalId, since the default recipient is always the treasury
defaultRoyaltyRecipient.minRoyaltyPercentage = _voucherInitValues.royaltyPercentage;
defaultRoyaltyRecipient.externalId = DEFAULT_ROYALTY_RECIPIENT;

// Calculate seller salt and check that it is unique
bytes32 sellerSalt = keccak256(abi.encodePacked(sender, _voucherInitValues.collectionSalt));
Expand All @@ -113,7 +113,7 @@ contract SellerBase is ProtocolBase, IBosonAccountEvents {

// Notify watchers of state change
emit SellerCreated(sellerId, _seller, voucherCloneAddress, _authToken, sender);
emit RoyaltyRecipientsChanged(sellerId, royaltyRecipients, sender);
emit RoyaltyRecipientsChanged(sellerId, fetchRoyaltyRecipients(sellerId), sender);
}

/**
Expand Down Expand Up @@ -234,4 +234,23 @@ contract SellerBase is ProtocolBase, IBosonAccountEvents {
sellerPendingUpdate.assistant != address(0) ||
authTokenPendingUpdate.tokenType != AuthTokenType.None;
}

/**
* @notice Gets seller's royalty recipients.
*
* @param _sellerId - seller id
* @return royaltyRecipients - list of royalty recipients
*/
function fetchRoyaltyRecipients(
uint256 _sellerId
) internal view returns (RoyaltyRecipient[] memory royaltyRecipients) {
royaltyRecipients = protocolLookups().royaltyRecipientsBySeller[_sellerId];

// If the seller did not change the default recipient name, return the default name
// royaltyRecipients[0] exists because the default recipient is always present
if (bytes(royaltyRecipients[0].externalId).length == 0) {
royaltyRecipients[0].externalId = DEFAULT_ROYALTY_RECIPIENT;
}
return royaltyRecipients;
}
}
73 changes: 71 additions & 2 deletions contracts/protocol/facets/ProtocolInitializationHandlerFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -94,21 +94,22 @@ contract ProtocolInitializationHandlerFacet is IBosonProtocolInitializationHandl
}
}

ProtocolLib.ProtocolStatus storage status = protocolStatus();
if (_isUpgrade) {
if (_version == bytes32("2.2.0")) {
initV2_2_0(_initializationData);
} else if (_version == bytes32("2.2.1")) {
initV2_2_1();
} else if (_version == bytes32("2.3.0")) {
initV2_3_0(_initializationData);
} else if (_version == bytes32("2.4.0")) {
initV2_4_0(_initializationData);
}
}

removeInterfaces(_interfacesToRemove);
addInterfaces(_interfacesToAdd);

status.version = _version;
protocolStatus().version = _version;

emit ProtocolInitialized(string(abi.encodePacked(_version)));
}
Expand Down Expand Up @@ -176,6 +177,74 @@ contract ProtocolInitializationHandlerFacet is IBosonProtocolInitializationHandl
protocolAddresses().beaconProxy = address(new BeaconClientProxy{ salt: VOUCHER_PROXY_SALT }());
}

/**
* @notice Initializes the version 2.4.0.
*
* Initialization data is used to back-fill the royalty recipients for existing offers and sellers.
* The data is grouped by royalty percentage, so if more sellers and/or have the same royalty percentage, they can be grouped together.
* Supplied royalty percentage should match the current percentage set in seller's boson voucher contract.
* If seller has multiple collections with different royalty precentages:
* - the sellerId should be included in the group, corresponding to the minimal royalty percentage
* - the _offerIds array should be included in the group, corresponding to the royalty percentage that matches the royalty of the collection to which offer belongs
* If some offer is voided, or has no active vouchers, it can be omitted.
*
* If the amount of data is too large, it can be split into multiple `initV2_4_0Public` calls, that should be made before calling initialize.
*
* N.B. this method does not validate that the seller exists, or that it's unique.
*
* Reverts if:
* - Current version is not 2.3.0
* - Length of _sellerIds, _royaltyPercentages and _offerIds arrays do not match
* - Any of the offerIds does not exist
*
* @param _initializationData - data representing uint256[] _sellerIds, uint256[] _royaltyPercentages, uint256[][] _offerIds
*/
function initV2_4_0(bytes calldata _initializationData) internal {
// Current version must be 2.3.0
if (protocolStatus().version != bytes32("2.3.0")) revert WrongCurrentVersion();

(uint256[] memory _royaltyPercentages, uint256[][] memory _sellerIds, uint256[][] memory _offerIds) = abi
.decode(_initializationData, (uint256[], uint256[][], uint256[][]));

if (_royaltyPercentages.length != _sellerIds.length || _royaltyPercentages.length != _offerIds.length)
revert ArrayLengthMismatch();
ProtocolLib.ProtocolLookups storage lookups = protocolLookups();

for (uint256 i = 0; i < _royaltyPercentages.length; i++) {
// Populate sellers' Royalty Recipients
for (uint256 j = 0; j < _sellerIds[i].length; j++) {
RoyaltyRecipient storage defaultRoyaltyRecipient = lookups
.royaltyRecipientsBySeller[_sellerIds[i][j]]
.push();
defaultRoyaltyRecipient.minRoyaltyPercentage = _royaltyPercentages[i];
}

// Populate offers' Royalty Info
for (uint256 j = 0; j < _offerIds[i].length; j++) {
(bool exist, Offer storage offer) = fetchOffer(_offerIds[i][j]);
if (!exist) revert NoSuchOffer();

RoyaltyInfo storage royaltyInfo = offer.royaltyInfo.push();
royaltyInfo.recipients.push(payable(address(0))); // default recipient
royaltyInfo.bps.push(_royaltyPercentages[i]);
}
}
}

/**
* @notice Method to initialize the protocol if it cannot be done in a single transaction.
*
* This should be used only if the amount of data is too large, and it cannot be done in a single `initialize` transaction.
* This method should be called before `initialize` method.
* This method should not be registered as a diamond public method.
* Refer to initV2_4_0 for more details about the data structure.
*
* @param _initializationData - data representing uint256[] _sellerIds, uint256[] _royaltyPercentages, uint256[][] _offerIds
*/
function initV2_4_0External(bytes calldata _initializationData) external onlyRole(UPGRADER) {
initV2_4_0(_initializationData);
}

/**
* @notice Gets the current protocol version.
*
Expand Down
13 changes: 7 additions & 6 deletions contracts/protocol/facets/SellerHandlerFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,9 @@ contract SellerHandlerFacet is SellerBase {
.royaltyRecipientIndexBySellerAndRecipient[_seller.id];
uint256 royaltyRecipientId = royaltyRecipientIndexBySellerAndRecipient[_seller.treasury];

RoyaltyRecipient[] storage royaltyRecipients = lookups.royaltyRecipientsBySeller[_seller.id];
if (royaltyRecipientId != 0) {
RoyaltyRecipient[] storage royaltyRecipients = lookups.royaltyRecipientsBySeller[_seller.id];

// If the new treasury is already a royalty recipient, remove it
royaltyRecipientId--; // royaltyRecipientId is 1-based, so we need to decrement it to get the index
uint256 lastRoyaltyRecipientsId = royaltyRecipients.length - 1;
Expand All @@ -178,7 +179,7 @@ contract SellerHandlerFacet is SellerBase {

updateApplied = true;

emit RoyaltyRecipientsChanged(_seller.id, royaltyRecipients, msgSender());
emit RoyaltyRecipientsChanged(_seller.id, fetchRoyaltyRecipients(_seller.id), msgSender());
}

if (keccak256(bytes(_seller.metadataUri)) != keccak256(bytes(seller.metadataUri))) {
Expand Down Expand Up @@ -505,7 +506,7 @@ contract SellerHandlerFacet is SellerBase {
}
}

emit RoyaltyRecipientsChanged(_sellerId, royaltyRecipients, sender);
emit RoyaltyRecipientsChanged(_sellerId, fetchRoyaltyRecipients(_sellerId), sender);
}

/**
Expand Down Expand Up @@ -584,7 +585,7 @@ contract SellerHandlerFacet is SellerBase {
}
}

emit RoyaltyRecipientsChanged(_sellerId, royaltyRecipients, msgSender());
emit RoyaltyRecipientsChanged(_sellerId, fetchRoyaltyRecipients(_sellerId), msgSender());
}

/**
Expand Down Expand Up @@ -648,7 +649,7 @@ contract SellerHandlerFacet is SellerBase {
}
}

emit RoyaltyRecipientsChanged(_sellerId, royaltyRecipients, sender);
emit RoyaltyRecipientsChanged(_sellerId, fetchRoyaltyRecipients(_sellerId), sender);
}

/**
Expand Down Expand Up @@ -845,7 +846,7 @@ contract SellerHandlerFacet is SellerBase {
function getRoyaltyRecipients(
uint256 _sellerId
) external view returns (RoyaltyRecipient[] memory royaltyRecipients) {
return protocolLookups().royaltyRecipientsBySeller[_sellerId];
return fetchRoyaltyRecipients(_sellerId);
}

/**
Expand Down
Loading

0 comments on commit 179efde

Please sign in to comment.