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

Remove amount input from transferToVault() function #324

Merged
merged 3 commits into from
Dec 3, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ interface IGraphAwareRoyaltyPolicy is IRoyaltyPolicy {
/// @param ipId The ipId of the IP asset
/// @param ancestorIpId The ancestor ipId of the IP asset
/// @param token The token address to transfer
/// @param amount The amount of tokens to transfer
function transferToVault(address ipId, address ancestorIpId, address token, uint256 amount) external;
/// @return The amount of revenue tokens transferred
function transferToVault(address ipId, address ancestorIpId, address token) external returns (uint256);

/// @notice Returns the royalty percentage between an IP asset and a given ancestor
/// @param ipId The ipId to get the royalty for
Expand Down
12 changes: 0 additions & 12 deletions contracts/lib/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -653,15 +653,9 @@ library Errors {
/// @notice Zero claimable royalty.
error RoyaltyPolicyLAP__ZeroClaimableRoyalty();

/// @notice Amount exceeds the claimable royalty.
error RoyaltyPolicyLAP__ExceedsClaimableRoyalty();

/// @notice Above maximum percentage.
error RoyaltyPolicyLAP__AboveMaxPercent();

/// @notice Zero amount provided.
error RoyaltyPolicyLAP__ZeroAmount();

////////////////////////////////////////////////////////////////////////////
// Royalty Policy LRP //
////////////////////////////////////////////////////////////////////////////
Expand All @@ -684,15 +678,9 @@ library Errors {
/// @notice Zero claimable royalty.
error RoyaltyPolicyLRP__ZeroClaimableRoyalty();

/// @notice Claimer is not an ancestor of the IP.
error RoyaltyPolicyLRP__ExceedsClaimableRoyalty();

/// @notice Above maximum percentage.
error RoyaltyPolicyLRP__AboveMaxPercent();

/// @notice Zero amount provided.
error RoyaltyPolicyLRP__ZeroAmount();

////////////////////////////////////////////////////////////////////////////
// IP Royalty Vault //
////////////////////////////////////////////////////////////////////////////
Expand Down
27 changes: 15 additions & 12 deletions contracts/modules/royalty/policies/LAP/RoyaltyPolicyLAP.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";

import { IRoyaltyModule } from "../../../../interfaces/modules/royalty/IRoyaltyModule.sol";
import { IGraphAwareRoyaltyPolicy } from "../../../../interfaces/modules/royalty/policies/IGraphAwareRoyaltyPolicy.sol";
Expand Down Expand Up @@ -124,12 +125,14 @@ contract RoyaltyPolicyLAP is
/// @param ipId The ipId of the IP asset
/// @param ancestorIpId The ancestor ipId of the IP asset
/// @param token The token address to transfer
/// @param amount The amount of tokens to transfer
function transferToVault(address ipId, address ancestorIpId, address token, uint256 amount) external whenNotPaused {
/// @return The amount of revenue tokens transferred
function transferToVault(
address ipId,
address ancestorIpId,
address token
) external whenNotPaused returns (uint256) {
RoyaltyPolicyLAPStorage storage $ = _getRoyaltyPolicyLAPStorage();

if (amount == 0) revert Errors.RoyaltyPolicyLAP__ZeroAmount();

uint32 ancestorPercent = $.ancestorPercentLAP[ipId][ancestorIpId];
if (ancestorPercent == 0) {
// on the first transfer to a vault from a specific descendant the royalty between the two is set
Expand All @@ -138,21 +141,21 @@ contract RoyaltyPolicyLAP is
$.ancestorPercentLAP[ipId][ancestorIpId] = ancestorPercent;
}

// check if the amount being claimed is within the claimable royalty amount
// calculate the amount to transfer
IRoyaltyModule royaltyModule = ROYALTY_MODULE;
uint256 totalRevenueTokens = royaltyModule.totalRevenueTokensReceived(ipId, token);
uint256 maxAmount = (totalRevenueTokens * ancestorPercent) / royaltyModule.maxPercent();
uint256 transferredAmount = $.transferredTokenLAP[ipId][ancestorIpId][token];
if (transferredAmount + amount > maxAmount) revert Errors.RoyaltyPolicyLAP__ExceedsClaimableRoyalty();
uint256 amountToTransfer = Math.min(maxAmount - transferredAmount, IERC20(token).balanceOf(address(this)));

// make the revenue token transfer
$.transferredTokenLAP[ipId][ancestorIpId][token] += amountToTransfer;
address ancestorIpRoyaltyVault = royaltyModule.ipRoyaltyVaults(ancestorIpId);
IIpRoyaltyVault(ancestorIpRoyaltyVault).updateVaultBalance(token, amountToTransfer);
IERC20(token).safeTransfer(ancestorIpRoyaltyVault, amountToTransfer);

$.transferredTokenLAP[ipId][ancestorIpId][token] += amount;

IIpRoyaltyVault(ancestorIpRoyaltyVault).updateVaultBalance(token, amount);
IERC20(token).safeTransfer(ancestorIpRoyaltyVault, amount);

emit RevenueTransferredToVault(ipId, ancestorIpId, token, amount);
emit RevenueTransferredToVault(ipId, ancestorIpId, token, amountToTransfer);
return amountToTransfer;
}

/// @notice Returns the amount of royalty tokens required to link a child to a given IP asset
Expand Down
27 changes: 15 additions & 12 deletions contracts/modules/royalty/policies/LRP/RoyaltyPolicyLRP.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";

import { IRoyaltyModule } from "../../../../interfaces/modules/royalty/IRoyaltyModule.sol";
import { IGraphAwareRoyaltyPolicy } from "../../../../interfaces/modules/royalty/policies/IGraphAwareRoyaltyPolicy.sol";
Expand Down Expand Up @@ -151,12 +152,14 @@ contract RoyaltyPolicyLRP is
/// @param ipId The ipId of the IP asset
/// @param ancestorIpId The ancestor ipId of the IP asset
/// @param token The token address to transfer
/// @param amount The amount of tokens to transfer
function transferToVault(address ipId, address ancestorIpId, address token, uint256 amount) external whenNotPaused {
/// @return The amount of revenue tokens transferred
function transferToVault(
address ipId,
address ancestorIpId,
address token
) external whenNotPaused returns (uint256) {
RoyaltyPolicyLRPStorage storage $ = _getRoyaltyPolicyLRPStorage();

if (amount == 0) revert Errors.RoyaltyPolicyLRP__ZeroAmount();

uint32 ancestorPercent = $.ancestorPercentLRP[ipId][ancestorIpId];
if (ancestorPercent == 0) {
// on the first transfer to a vault from a specific descendant the royalty between the two is set
Expand All @@ -165,21 +168,21 @@ contract RoyaltyPolicyLRP is
$.ancestorPercentLRP[ipId][ancestorIpId] = ancestorPercent;
}

// check if the amount being claimed is within the claimable royalty amount
// calculate the amount to transfer
IRoyaltyModule royaltyModule = ROYALTY_MODULE;
uint256 totalRevenueTokens = royaltyModule.totalRevenueTokensReceived(ipId, token);
uint256 maxAmount = (totalRevenueTokens * ancestorPercent) / royaltyModule.maxPercent();
uint256 transferredAmount = $.transferredTokenLRP[ipId][ancestorIpId][token];
if (transferredAmount + amount > maxAmount) revert Errors.RoyaltyPolicyLRP__ExceedsClaimableRoyalty();
uint256 amountToTransfer = Math.min(maxAmount - transferredAmount, IERC20(token).balanceOf(address(this)));

// make the revenue token transfer
$.transferredTokenLRP[ipId][ancestorIpId][token] += amountToTransfer;
address ancestorIpRoyaltyVault = royaltyModule.ipRoyaltyVaults(ancestorIpId);
IIpRoyaltyVault(ancestorIpRoyaltyVault).updateVaultBalance(token, amountToTransfer);
IERC20(token).safeTransfer(ancestorIpRoyaltyVault, amountToTransfer);

$.transferredTokenLRP[ipId][ancestorIpId][token] += amount;

IIpRoyaltyVault(ancestorIpRoyaltyVault).updateVaultBalance(token, amount);
IERC20(token).safeTransfer(ancestorIpRoyaltyVault, amount);

emit RevenueTransferredToVault(ipId, ancestorIpId, token, amount);
emit RevenueTransferredToVault(ipId, ancestorIpId, token, amountToTransfer);
return amountToTransfer;
}

/// @notice Returns the amount of royalty tokens required to link a child to a given IP asset
Expand Down
7 changes: 1 addition & 6 deletions test/foundry/integration/flows/grouping/Grouping.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,7 @@ contract Flows_Integration_Grouping is BaseIntegration {
ERC20[] memory tokens = new ERC20[](1);
tokens[0] = mockToken;

royaltyPolicyLAP.transferToVault(
ipAcct[3],
groupId,
address(mockToken),
(10 ether * 10_000_000) / royaltyModule.maxPercent()
);
royaltyPolicyLAP.transferToVault(ipAcct[3], groupId, address(mockToken));

vm.warp(block.timestamp + 7 days + 1);

Expand Down
20 changes: 7 additions & 13 deletions test/foundry/integration/flows/royalty/Royalty.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -182,18 +182,8 @@ contract Flows_Integration_Disputes is BaseIntegration {
uint256 earningsFromMintingFees = 4 * mintingFee;
assertEq(mockToken.balanceOf(vault), earningsFromMintingFees);

royaltyPolicyLAP.transferToVault(
ipAcct[2],
ipAcct[1],
address(mockToken),
(1 ether * 10_000_000) / royaltyModule.maxPercent()
);
royaltyPolicyLAP.transferToVault(
ipAcct[3],
ipAcct[1],
address(mockToken),
(1 ether * 20_000_000) / royaltyModule.maxPercent()
);
royaltyPolicyLAP.transferToVault(ipAcct[2], ipAcct[1], address(mockToken));
royaltyPolicyLAP.transferToVault(ipAcct[3], ipAcct[1], address(mockToken));

vm.warp(block.timestamp + 7 days + 1);

Expand All @@ -205,7 +195,11 @@ contract Flows_Integration_Disputes is BaseIntegration {

assertEq(
aliceBalanceAfter - aliceBalanceBefore,
earningsFromMintingFees + (1 ether * (10_000_000 + 20_000_000)) / royaltyModule.maxPercent()
earningsFromMintingFees +
(1 ether * 20_000_000) /
royaltyModule.maxPercent() + // 20% of the 1 ether payment made to IPAccount3
(mintingFee * 10_000_000) /
royaltyModule.maxPercent() // 10% of the 7 ether mintingFee IPAaccount2 received
);
}

Expand Down
2 changes: 1 addition & 1 deletion test/foundry/mocks/policy/MockRoyaltyPolicyLAP.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ contract MockRoyaltyPolicyLAP is IGraphAwareRoyaltyPolicy {
function revenueTokenBalances(address ipId, address token) external view returns (uint256) {}
function snapshotsClaimed(address ipId, address token, uint256 snapshot) external view returns (bool) {}
function snapshotsClaimedCounter(address ipId, address token) external view returns (uint256) {}
function transferToVault(address ipId, address ancestorIpId, address token, uint256 amount) external {}
function transferToVault(address ipId, address ancestorIpId, address token) external returns (uint256) {}
function getPolicyRoyalty(address ipId, address ancestorIpId) external view returns (uint32) {}
function getAncestorPercent(address ipId, address ancestorIpId) external view returns (uint32) {}
function getTransferredTokens(address ipId, address ancestorIpId, address token) external view returns (uint256) {}
Expand Down
2 changes: 1 addition & 1 deletion test/foundry/modules/grouping/GroupingModule.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ contract GroupingModuleTest is BaseTest {
erc20.approve(address(royaltyModule), 1000);
royaltyModule.payRoyaltyOnBehalf(ipId3, ipOwner3, address(erc20), 1000);
vm.stopPrank();
royaltyPolicyLAP.transferToVault(ipId3, groupId, address(erc20), 100);
royaltyPolicyLAP.transferToVault(ipId3, groupId, address(erc20));
vm.warp(vm.getBlockTimestamp() + 7 days);

vm.expectEmit();
Expand Down
4 changes: 2 additions & 2 deletions test/foundry/modules/licensing/LicensingModule.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1819,8 +1819,8 @@ contract LicensingModuleTest is BaseTest {
vm.startPrank(ipOwner3);
erc20.approve(address(royaltyModule), 1000);
royaltyModule.payRoyaltyOnBehalf(ipId3, address(0), address(erc20), 1000);
royaltyPolicyLAP.transferToVault(ipId3, ipId2, address(erc20), 100);
royaltyPolicyLAP.transferToVault(ipId3, ipId1, address(erc20), 10);
royaltyPolicyLAP.transferToVault(ipId3, ipId2, address(erc20));
royaltyPolicyLAP.transferToVault(ipId3, ipId1, address(erc20));
vm.stopPrank();
assertEq(erc20.balanceOf(royaltyModule.ipRoyaltyVaults(ipId2)), 100);
assertEq(erc20.balanceOf(royaltyModule.ipRoyaltyVaults(ipId1)), 10);
Expand Down
42 changes: 2 additions & 40 deletions test/foundry/modules/royalty/LAP/RoyaltyPolicyLAP.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,6 @@ contract TestRoyaltyPolicyLAP is BaseTest {
assertEq(royaltyPolicyLAP.getPolicyRoyalty(address(80), address(30)), 20 * 10 ** 6);
}

function test_RoyaltyPolicyLAP_transferToVault_revert_ZeroAmount() public {
vm.expectRevert(Errors.RoyaltyPolicyLAP__ZeroAmount.selector);
royaltyPolicyLAP.transferToVault(address(80), address(10), address(USDC), 0);
}

function test_RoyaltyPolicyLAP_transferToVault_revert_ZeroClaimableRoyalty() public {
address[] memory parents = new address[](3);
address[] memory licenseRoyaltyPolicies = new address[](3);
Expand Down Expand Up @@ -214,42 +209,9 @@ contract TestRoyaltyPolicyLAP is BaseTest {

// first transfer to vault
vm.expectRevert(Errors.RoyaltyPolicyLAP__ZeroClaimableRoyalty.selector);
royaltyPolicyLAP.transferToVault(ipAccount1, address(2000), address(USDC), 100 * 10 ** 6);
royaltyPolicyLAP.transferToVault(ipAccount1, address(2000), address(USDC));
}

function test_RoyaltyPolicyLAP_transferToVault_revert_ExceedsClaimableRoyalty() public {
address[] memory parents = new address[](3);
address[] memory licenseRoyaltyPolicies = new address[](3);
uint32[] memory parentRoyalties = new uint32[](3);
parents[0] = address(10);
parents[1] = address(20);
parents[2] = address(30);
licenseRoyaltyPolicies[0] = address(royaltyPolicyLAP);
licenseRoyaltyPolicies[1] = address(royaltyPolicyLAP);
licenseRoyaltyPolicies[2] = address(royaltyPolicyLAP);
parentRoyalties[0] = uint32(10 * 10 ** 6);
parentRoyalties[1] = uint32(15 * 10 ** 6);
parentRoyalties[2] = uint32(20 * 10 ** 6);
ipGraph.addParentIp(ipAccount1, parents);

vm.startPrank(address(licensingModule));
royaltyModule.onLinkToParents(ipAccount1, parents, licenseRoyaltyPolicies, parentRoyalties, "", 100e6);

// make payment to ip 80
uint256 royaltyAmount = 100 * 10 ** 6;
address receiverIpId = ipAccount1;
address payerIpId = address(3);
vm.startPrank(payerIpId);
USDC.mint(payerIpId, royaltyAmount);
USDC.approve(address(royaltyModule), royaltyAmount);
royaltyModule.payRoyaltyOnBehalf(receiverIpId, payerIpId, address(USDC), royaltyAmount);
vm.stopPrank();

royaltyPolicyLAP.transferToVault(ipAccount1, address(10), address(USDC), 5 * 10 ** 6);

vm.expectRevert(Errors.RoyaltyPolicyLAP__ExceedsClaimableRoyalty.selector);
royaltyPolicyLAP.transferToVault(ipAccount1, address(10), address(USDC), 6 * 10 ** 6);
}
function test_RoyaltyPolicyLAP_transferToVault() public {
address[] memory parents = new address[](3);
address[] memory licenseRoyaltyPolicies = new address[](3);
Expand Down Expand Up @@ -288,7 +250,7 @@ contract TestRoyaltyPolicyLAP is BaseTest {
vm.expectEmit(true, true, true, true, address(royaltyPolicyLAP));
emit RevenueTransferredToVault(ipAccount1, address(10), address(USDC), 10 * 10 ** 6);

royaltyPolicyLAP.transferToVault(ipAccount1, address(10), address(USDC), 10 * 10 ** 6);
royaltyPolicyLAP.transferToVault(ipAccount1, address(10), address(USDC));

uint256 transferredAmountAfter = royaltyPolicyLAP.getTransferredTokens(ipAccount1, address(10), address(USDC));
uint256 usdcAncestorVaultBalanceAfter = USDC.balanceOf(ancestorIpRoyaltyVault);
Expand Down
45 changes: 3 additions & 42 deletions test/foundry/modules/royalty/LRP/RoyaltyPolicyLRP.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,6 @@ contract TestRoyaltyPolicyLRP is BaseTest {
assertEq(royaltyPolicyLRP.getPolicyRoyalty(address(80), address(30)), 20 * 10 ** 6);
}

function test_RoyaltyPolicyLRP_transferToVault_revert_ZeroAmount() public {
vm.expectRevert(Errors.RoyaltyPolicyLRP__ZeroAmount.selector);
royaltyPolicyLRP.transferToVault(address(80), address(10), address(USDC), 0);
}

function test_RoyaltyPolicyLRP_transferToVault_revert_ZeroClaimableRoyalty() public {
address[] memory parents = new address[](3);
address[] memory licenseRoyaltyPolicies = new address[](3);
Expand Down Expand Up @@ -223,42 +218,8 @@ contract TestRoyaltyPolicyLRP is BaseTest {
vm.stopPrank();

// first transfer to vault
vm.expectRevert();
royaltyPolicyLRP.transferToVault(ipAccount1, address(10), address(USDC), 100 * 10 ** 6);
}

function test_RoyaltyPolicyLRP_transferToVault_revert_ExceedsClaimableRoyalty() public {
address[] memory parents = new address[](3);
address[] memory licenseRoyaltyPolicies = new address[](3);
uint32[] memory parentRoyalties = new uint32[](3);
parents[0] = address(10);
parents[1] = address(20);
parents[2] = address(30);
licenseRoyaltyPolicies[0] = address(royaltyPolicyLRP);
licenseRoyaltyPolicies[1] = address(royaltyPolicyLRP);
licenseRoyaltyPolicies[2] = address(royaltyPolicyLRP);
parentRoyalties[0] = uint32(10 * 10 ** 6);
parentRoyalties[1] = uint32(15 * 10 ** 6);
parentRoyalties[2] = uint32(20 * 10 ** 6);
ipGraph.addParentIp(ipAccount1, parents);

vm.startPrank(address(licensingModule));
royaltyModule.onLinkToParents(ipAccount1, parents, licenseRoyaltyPolicies, parentRoyalties, "", 100e6);

// make payment to ip 80
uint256 royaltyAmount = 100 * 10 ** 6;
address receiverIpId = ipAccount1;
address payerIpId = address(3);
vm.startPrank(payerIpId);
USDC.mint(payerIpId, royaltyAmount);
USDC.approve(address(royaltyModule), royaltyAmount);
royaltyModule.payRoyaltyOnBehalf(receiverIpId, payerIpId, address(USDC), royaltyAmount);
vm.stopPrank();

royaltyPolicyLRP.transferToVault(ipAccount1, address(10), address(USDC), 5 * 10 ** 6);

vm.expectRevert(Errors.RoyaltyPolicyLRP__ExceedsClaimableRoyalty.selector);
royaltyPolicyLRP.transferToVault(ipAccount1, address(10), address(USDC), 6 * 10 ** 6);
vm.expectRevert(); // throws out-of-gas instead of ZeroClaimableRoyalty due to using the mock ip graph
royaltyPolicyLRP.transferToVault(ipAccount1, address(2000), address(USDC));
}

function test_RoyaltyPolicyLRP_transferToVault() public {
Expand Down Expand Up @@ -299,7 +260,7 @@ contract TestRoyaltyPolicyLRP is BaseTest {
uint256 usdcAncestorVaultBalanceBefore = USDC.balanceOf(ancestorIpRoyaltyVault);
uint256 usdcLRPContractBalanceBefore = USDC.balanceOf(address(royaltyPolicyLRP));

royaltyPolicyLRP.transferToVault(ipAccount1, address(10), address(USDC), 10 * 10 ** 6);
royaltyPolicyLRP.transferToVault(ipAccount1, address(10), address(USDC));

uint256 transferredAmountAfter = royaltyPolicyLRP.getTransferredTokens(ipAccount1, address(10), address(USDC));
uint256 usdcAncestorVaultBalanceAfter = USDC.balanceOf(ancestorIpRoyaltyVault);
Expand Down
Loading