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

Royalty fixes #78

Merged
merged 5 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ interface IIpRoyaltyVault {

/// @notice Allows token holders to claim revenue token based on the token balance at certain snapshot
/// @param snapshotId The snapshot id
/// @param tokens The list of revenue tokens to claim
function claimRevenueByTokenBatch(uint256 snapshotId, address[] calldata tokens) external;
/// @param tokenList The list of revenue tokens to claim
function claimRevenueByTokenBatch(uint256 snapshotId, address[] calldata tokenList) external;

/// @notice Allows token holders to claim by a list of snapshot ids based on the token balance at certain snapshot
/// @param snapshotIds The list of snapshot ids
Expand Down
2 changes: 2 additions & 0 deletions contracts/lib/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ library Errors {
error RoyaltyModule__NoParentsOnLinking();
error RoyaltyModule__ZeroDisputeModule();
error RoyaltyModule__IpIsTagged();
error RoyaltyModule__ZeroAccessManager();

error RoyaltyPolicyLAP__ZeroRoyaltyModule();
error RoyaltyPolicyLAP__ZeroLiquidSplitFactory();
Expand All @@ -270,6 +271,7 @@ library Errors {
error RoyaltyPolicyLAP__UnlinkableToParents();
error RoyaltyPolicyLAP__LastPositionNotAbleToMintLicense();
error RoyaltyPolicyLAP__ZeroIpRoyaltyVaultBeacon();
error RoyaltyPolicyLAP__ZeroAccessManager();

error IpRoyaltyVault__ZeroIpId();
error IpRoyaltyVault__ZeroRoyaltyPolicyLAP();
Expand Down
3 changes: 2 additions & 1 deletion contracts/modules/royalty/RoyaltyModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ contract RoyaltyModule is
/// @notice initializer for this implementation contract
/// @param accessManager The address of the protocol admin roles contract
function initialize(address accessManager) external initializer {
if (accessManager == address(0)) revert Errors.RoyaltyModule__ZeroAccessManager();
__AccessManaged_init(accessManager);
__ReentrancyGuard_init();
__UUPSUpgradeable_init();
Expand Down Expand Up @@ -132,7 +133,7 @@ contract RoyaltyModule is

// if the node is a root node, then royaltyPolicyIpId will be address(0) and any type of royalty type can be
// selected to mint a license if the node is a derivative node, then the any minted licenses by the derivative
// node should have the same royalty policy as the parent node a derivative node set its royalty policy
// node should have the same royalty policy as the parent node and a derivative node set its royalty policy
// immutably in onLinkToParents() function below
if (royaltyPolicyIpId != royaltyPolicy && royaltyPolicyIpId != address(0))
revert Errors.RoyaltyModule__CanOnlyMintSelectedPolicy();
Expand Down
50 changes: 26 additions & 24 deletions contracts/modules/royalty/policies/IpRoyaltyVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,6 @@ contract IpRoyaltyVault is IIpRoyaltyVault, ERC20SnapshotUpgradeable, Reentrancy
uint32 unclaimedTokens,
address ipIdAddress
) external initializer {
if (ipIdAddress == address(0)) revert Errors.IpRoyaltyVault__ZeroIpId();

LeoHChen marked this conversation as resolved.
Show resolved Hide resolved
IpRoyaltyVaultStorage storage $ = _getIpRoyaltyVaultStorage();

$.ipId = ipIdAddress;
Expand All @@ -102,6 +100,10 @@ contract IpRoyaltyVault is IIpRoyaltyVault, ERC20SnapshotUpgradeable, Reentrancy
__ERC20_init(name, symbol);
}

/// @notice Returns the number royalty token decimals
function decimals() public view override returns (uint8) {
return 6;
}
/// @notice Adds a new revenue token to the vault
/// @param token The address of the revenue token
/// @dev Only callable by the royalty policy LAP
Expand All @@ -125,24 +127,24 @@ contract IpRoyaltyVault is IIpRoyaltyVault, ERC20SnapshotUpgradeable, Reentrancy
uint32 unclaimedTokens = $.unclaimedRoyaltyTokens;
$.unclaimedAtSnapshot[snapshotId] = unclaimedTokens;

address[] memory tokens = $.tokens.values();
address[] memory tokenList = $.tokens.values();

for (uint256 i = 0; i < tokens.length; i++) {
uint256 tokenBalance = IERC20Upgradeable(tokens[i]).balanceOf(address(this));
for (uint256 i = 0; i < tokenList.length; i++) {
uint256 tokenBalance = IERC20Upgradeable(tokenList[i]).balanceOf(address(this));
if (tokenBalance == 0) {
$.tokens.remove(tokens[i]);
$.tokens.remove(tokenList[i]);
continue;
}

uint256 newRevenue = tokenBalance - $.claimVaultAmount[tokens[i]] - $.ancestorsVaultAmount[tokens[i]];
uint256 newRevenue = tokenBalance - $.claimVaultAmount[tokenList[i]] - $.ancestorsVaultAmount[tokenList[i]];
if (newRevenue == 0) continue;

uint256 ancestorsTokens = (newRevenue * unclaimedTokens) / totalSupply();
$.ancestorsVaultAmount[tokens[i]] += ancestorsTokens;
$.ancestorsVaultAmount[tokenList[i]] += ancestorsTokens;

uint256 claimableTokens = newRevenue - ancestorsTokens;
$.claimableAtSnapshot[snapshotId][tokens[i]] = claimableTokens;
$.claimVaultAmount[tokens[i]] += claimableTokens;
$.claimableAtSnapshot[snapshotId][tokenList[i]] = claimableTokens;
$.claimVaultAmount[tokenList[i]] += claimableTokens;
}

emit SnapshotCompleted(snapshotId, block.timestamp, unclaimedTokens);
Expand All @@ -161,19 +163,19 @@ contract IpRoyaltyVault is IIpRoyaltyVault, ERC20SnapshotUpgradeable, Reentrancy

/// @notice Allows token holders to claim revenue token based on the token balance at certain snapshot
/// @param snapshotId The snapshot id
/// @param tokens The list of revenue tokens to claim
function claimRevenueByTokenBatch(uint256 snapshotId, address[] calldata tokens) external nonReentrant {
/// @param tokenList The list of revenue tokens to claim
function claimRevenueByTokenBatch(uint256 snapshotId, address[] calldata tokenList) external nonReentrant {
IpRoyaltyVaultStorage storage $ = _getIpRoyaltyVaultStorage();

for (uint256 i = 0; i < tokens.length; i++) {
uint256 claimableToken = _claimableRevenue(msg.sender, snapshotId, tokens[i]);
for (uint256 i = 0; i < tokenList.length; i++) {
uint256 claimableToken = _claimableRevenue(msg.sender, snapshotId, tokenList[i]);
if (claimableToken == 0) continue;

$.isClaimedAtSnapshot[snapshotId][msg.sender][tokens[i]] = true;
$.claimVaultAmount[tokens[i]] -= claimableToken;
IERC20Upgradeable(tokens[i]).safeTransfer(msg.sender, claimableToken);
$.isClaimedAtSnapshot[snapshotId][msg.sender][tokenList[i]] = true;
$.claimVaultAmount[tokenList[i]] -= claimableToken;
IERC20Upgradeable(tokenList[i]).safeTransfer(msg.sender, claimableToken);

emit RevenueTokenClaimed(msg.sender, tokens[i], claimableToken);
emit RevenueTokenClaimed(msg.sender, tokenList[i], claimableToken);
}
}

Expand Down Expand Up @@ -246,19 +248,19 @@ contract IpRoyaltyVault is IIpRoyaltyVault, ERC20SnapshotUpgradeable, Reentrancy
function _collectAccruedTokens(uint256 royaltyTokensToClaim, address ancestorIpId) internal {
IpRoyaltyVaultStorage storage $ = _getIpRoyaltyVaultStorage();

address[] memory tokens = $.tokens.values();
address[] memory tokenList = $.tokens.values();

for (uint256 i = 0; i < tokens.length; ++i) {
for (uint256 i = 0; i < tokenList.length; ++i) {
// the only case in which unclaimedRoyaltyTokens can be 0 is when the vault is empty and everyone claimed
// in which case the call will revert upstream with IpRoyaltyVault__AlreadyClaimed error
uint256 collectAmount = ($.ancestorsVaultAmount[tokens[i]] * royaltyTokensToClaim) /
uint256 collectAmount = ($.ancestorsVaultAmount[tokenList[i]] * royaltyTokensToClaim) /
$.unclaimedRoyaltyTokens;
if (collectAmount == 0) continue;

$.ancestorsVaultAmount[tokens[i]] -= collectAmount;
IERC20Upgradeable(tokens[i]).safeTransfer(ancestorIpId, collectAmount);
$.ancestorsVaultAmount[tokenList[i]] -= collectAmount;
IERC20Upgradeable(tokenList[i]).safeTransfer(ancestorIpId, collectAmount);

emit RevenueTokenClaimed(ancestorIpId, tokens[i], collectAmount);
emit RevenueTokenClaimed(ancestorIpId, tokenList[i], collectAmount);
}
}

Expand Down
7 changes: 4 additions & 3 deletions contracts/modules/royalty/policies/RoyaltyPolicyLAP.sol
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,10 @@ contract RoyaltyPolicyLAP is IRoyaltyPolicyLAP, AccessManagedUpgradeable, Reentr
}

/// @notice Initializer for this implementation contract
/// @param governance The governance address
function initialize(address governance) external initializer {
__AccessManaged_init(governance);
/// @param accessManager The address of the protocol admin roles contract
function initialize(address accessManager) external initializer {
if (accessManager == address(0)) revert Errors.RoyaltyPolicyLAP__ZeroAccessManager();
__AccessManaged_init(accessManager);
__ReentrancyGuard_init();
__UUPSUpgradeable_init();
}
Expand Down
Loading
Loading