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

fix(royalty): update RoyaltyWorkflows to reflect core protocol royalty policy changes #139

Merged
merged 1 commit into from
Dec 11, 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
23 changes: 0 additions & 23 deletions contracts/interfaces/workflows/IRoyaltyWorkflows.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,6 @@ pragma solidity 0.8.26;
/// @title Royalty Workflows Interface
/// @notice Interface for IP royalty workflows.
interface IRoyaltyWorkflows {
/// @notice Transfers specified amounts of royalties from various royalty policies to the royalty
/// vault of an ancestor IP, and claims all the revenue for each currency token from the
/// ancestor IP's royalty vault to the claimer.
/// @param ancestorIpId The address of the ancestor IP from which the revenue is being claimed.
/// @param claimer The address of the claimer of the currency (revenue) tokens.
/// @param childIpIds The addresses of the child IPs from which royalties are derived.
/// @param royaltyPolicies The addresses of the royalty policies, where royaltyPolicies[i] governs
/// the royalty flow for childIpIds[i].
/// @param currencyTokens The addresses of the currency tokens in which royalties will be claimed,
/// where currencyTokens[i] is the token used for royalties from childIpIds[i].
/// @param amounts The amounts to transfer and claim, where amounts[i] represents the amount of
/// royalties in currencyTokens[i] to transfer from childIpIds[i]'s royaltyPolicies[i] to the ancestor's
/// royalty vault.
/// @return amountsClaimed The amounts of successfully claimed revenue for each specified currency token.
function transferToVaultAndClaimByTokenBatch(
address ancestorIpId,
address claimer,
address[] calldata childIpIds,
address[] calldata royaltyPolicies,
address[] calldata currencyTokens,
uint256[] calldata amounts
) external returns (uint256[] memory amountsClaimed);

/// @notice Transfers all avaiable royalties from various royalty policies to the royalty
/// vault of an ancestor IP, and claims all the revenue for each currency token
/// from the ancestor IP's royalty vault to the claimer.
Expand Down
61 changes: 1 addition & 60 deletions contracts/workflows/RoyaltyWorkflows.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,48 +42,6 @@ contract RoyaltyWorkflows is IRoyaltyWorkflows, MulticallUpgradeable, AccessMana
__UUPSUpgradeable_init();
}

/// @notice Transfers specified amounts of royalties from various royalty policies to the royalty
/// vault of an ancestor IP, and claims all the revenue for each currency token from the
/// ancestor IP's royalty vault to the claimer.
/// @param ancestorIpId The address of the ancestor IP from which the revenue is being claimed.
/// @param claimer The address of the claimer of the currency (revenue) tokens.
/// @param childIpIds The addresses of the child IPs from which royalties are derived.
/// @param royaltyPolicies The addresses of the royalty policies, where royaltyPolicies[i] governs
/// the royalty flow for childIpIds[i].
/// @param currencyTokens The addresses of the currency tokens in which royalties will be claimed,
/// where currencyTokens[i] is the token used for royalties from childIpIds[i].
/// @param amounts The amounts to transfer and claim, where amounts[i] represents the amount of
/// royalties in currencyTokens[i] to transfer from childIpIds[i]'s royaltyPolicies[i] to the ancestor's
/// royalty vault.
/// @return amountsClaimed The amounts of successfully claimed revenue for each specified currency token.
function transferToVaultAndClaimByTokenBatch(
address ancestorIpId,
address claimer,
address[] calldata childIpIds,
address[] calldata royaltyPolicies,
address[] calldata currencyTokens,
uint256[] calldata amounts
) external returns (uint256[] memory amountsClaimed) {
// Transfers to ancestor's vault an amount of revenue tokens claimable via the given royalty policy
for (uint256 i = 0; i < childIpIds.length; i++) {
IGraphAwareRoyaltyPolicy(royaltyPolicies[i]).transferToVault({
ipId: childIpIds[i],
ancestorIpId: ancestorIpId,
token: currencyTokens[i],
amount: amounts[i]
});
}

// Gets the ancestor IP's royalty vault
IIpRoyaltyVault ancestorIpRoyaltyVault = IIpRoyaltyVault(ROYALTY_MODULE.ipRoyaltyVaults(ancestorIpId));

// Claims revenue for each specified currency token
amountsClaimed = ancestorIpRoyaltyVault.claimRevenueOnBehalfByTokenBatch({
claimer: claimer,
tokenList: _getUniqueCurrencyTokens(currencyTokens)
});
}

/// @notice Transfers all avaiable royalties from various royalty policies to the royalty
/// vault of an ancestor IP, and claims all the revenue for each currency token
/// from the ancestor IP's royalty vault to the claimer.
Expand All @@ -103,28 +61,11 @@ contract RoyaltyWorkflows is IRoyaltyWorkflows, MulticallUpgradeable, AccessMana
address[] calldata currencyTokens
) external returns (uint256[] memory amountsClaimed) {
for (uint256 i = 0; i < childIpIds.length; i++) {
// Gets the total lifetime revenue tokens received for a given IP asset
uint256 totalTokenReceivedByChild = ROYALTY_MODULE.totalRevenueTokensReceived({
ipId: childIpIds[i],
token: currencyTokens[i]
});

// Gets the total lifetime revenue tokens transferred to a vault from a descendant IP via the policy
uint256 totalTokenTransferredToAncestor = IGraphAwareRoyaltyPolicy(royaltyPolicies[i])
.getTransferredTokens({ ipId: childIpIds[i], ancestorIpId: ancestorIpId, token: currencyTokens[i] });

uint32 ancestorPercentage = IGraphAwareRoyaltyPolicy(royaltyPolicies[i]).getPolicyRoyalty({
ipId: childIpIds[i],
ancestorIpId: ancestorIpId
});

// Transfer all available revenue tokens to the ancestor's vault
IGraphAwareRoyaltyPolicy(royaltyPolicies[i]).transferToVault({
ipId: childIpIds[i],
ancestorIpId: ancestorIpId,
token: currencyTokens[i],
amount: ((totalTokenReceivedByChild * ancestorPercentage) / ROYALTY_MODULE.maxPercent()) -
totalTokenTransferredToAncestor
token: currencyTokens[i]
});
}

Expand Down
3 changes: 0 additions & 3 deletions docs/WORKFLOWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,5 @@

### [Royalty Workflows](../contracts/interfaces/workflows/IRoyaltyWorkflows.sol)

- `transferToVaultAndClaimByTokenBatch`:
- Transfers specified amounts of royalties from various royalty policies to the royalty vault of the ancestor IP -> Claims all the revenue in each currency token from the ancestor IP's royalty vault to the claimer.

- `claimAllRevenue`:
- Transfers all avaiable royalties from various royalty policies to the royalty vault of the ancestor IP -> Claims all the revenue in each currency token from the ancestor IP's royalty vault to the claimer.
14 changes: 2 additions & 12 deletions test/integration/workflows/GroupingIntegration.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -261,23 +261,13 @@ contract GroupingIntegration is BaseIntegration {
StoryUSD.mint(testSender, amount1);
StoryUSD.approve(address(royaltyModule), amount1);
royaltyModule.payRoyaltyOnBehalf(ipId1, testSender, address(StoryUSD), amount1);
IGraphAwareRoyaltyPolicy(royaltyPolicyLAPAddr).transferToVault(
ipId1,
newGroupId,
address(StoryUSD),
(amount1 * revShare) / royaltyModule.maxPercent()
);
IGraphAwareRoyaltyPolicy(royaltyPolicyLAPAddr).transferToVault(ipId1, newGroupId, address(StoryUSD));

uint256 amount2 = 10_000 * 10 ** StoryUSD.decimals(); // 10,000 tokens
StoryUSD.mint(testSender, amount2);
StoryUSD.approve(address(royaltyModule), amount2);
royaltyModule.payRoyaltyOnBehalf(ipId2, testSender, address(StoryUSD), amount2);
IGraphAwareRoyaltyPolicy(royaltyPolicyLAPAddr).transferToVault(
ipId2,
newGroupId,
address(StoryUSD),
(amount2 * revShare) / royaltyModule.maxPercent()
);
IGraphAwareRoyaltyPolicy(royaltyPolicyLAPAddr).transferToVault(ipId2, newGroupId, address(StoryUSD));

address[] memory royaltyTokens = new address[](1);
royaltyTokens[0] = address(StoryUSD);
Expand Down
59 changes: 0 additions & 59 deletions test/integration/workflows/RoyaltyIntegration.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,69 +44,10 @@ contract RoyaltyIntegration is BaseIntegration {
super.run();
_beginBroadcast();
_setupTest();
_test_RoyaltyIntegration_transferToVaultAndClaimByTokenBatch();
_test_RoyaltyIntegration_claimAllRevenue();
_endBroadcast();
}

function _test_RoyaltyIntegration_transferToVaultAndClaimByTokenBatch()
private
logTest("test_RoyaltyIntegration_transferToVaultAndClaimByTokenBatch")
{
// setup IP graph
_setupIpGraph();

address[] memory childIpIds = new address[](3);
address[] memory royaltyPolicies = new address[](3);
address[] memory currencyTokens = new address[](3);
uint256[] memory amounts = new uint256[](3);

childIpIds[0] = childIpIdA;
royaltyPolicies[0] = royaltyPolicyLRPAddr;
currencyTokens[0] = address(StoryUSD);
amounts[0] = 10 ether;

childIpIds[1] = childIpIdB;
royaltyPolicies[1] = royaltyPolicyLRPAddr;
currencyTokens[1] = address(StoryUSD);
amounts[1] = 10 ether;

childIpIds[2] = grandChildIpId;
royaltyPolicies[2] = royaltyPolicyLRPAddr;
currencyTokens[2] = address(StoryUSD);
amounts[2] = 2 ether;

childIpIds[3] = childIpIdC;
royaltyPolicies[3] = royaltyPolicyLAPAddr;
currencyTokens[3] = address(StoryUSD);
amounts[3] = 10 ether;

uint256 claimerBalanceBefore = StoryUSD.balanceOf(ancestorIpId);

uint256[] memory amountsClaimed = royaltyWorkflows.transferToVaultAndClaimByTokenBatch({
ancestorIpId: ancestorIpId,
claimer: ancestorIpId,
childIpIds: childIpIds,
royaltyPolicies: royaltyPolicies,
currencyTokens: currencyTokens,
amounts: amounts
});

uint256 claimerBalanceAfter = StoryUSD.balanceOf(ancestorIpId);

assertEq(amountsClaimed.length, 1); // there is 1 currency token
assertEq(claimerBalanceAfter - claimerBalanceBefore, amountsClaimed[0]);
assertEq(
claimerBalanceAfter - claimerBalanceBefore,
defaultMintingFeeA +
defaultMintingFeeA + // 1000 + 1000 from minting fee of childIpA and childIpB
10 ether + // 10 currency tokens from childIpA transferred to vault
10 ether + // 10 currency tokens from childIpB transferred to vault
2 ether + // 2 currency tokens from grandChildIp transferred to vault
10 ether // 10 currency tokens from childIpC transferred to vault
);
}

function _test_RoyaltyIntegration_claimAllRevenue() private logTest("test_RoyaltyIntegration_claimAllRevenue") {
// setup IP graph
_setupIpGraph();
Expand Down
14 changes: 2 additions & 12 deletions test/workflows/GroupingWorkflows.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -339,25 +339,15 @@ contract GroupingWorkflowsTest is BaseTest {
vm.startPrank(ipOwner1);
mockToken.approve(address(royaltyModule), amount1);
royaltyModule.payRoyaltyOnBehalf(ipId1, ipOwner1, address(mockToken), amount1);
royaltyPolicyLAP.transferToVault(
ipId1,
newGroupId,
address(mockToken),
(amount1 * revShare) / royaltyModule.maxPercent()
);
royaltyPolicyLAP.transferToVault(ipId1, newGroupId, address(mockToken));
vm.stopPrank();

uint256 amount2 = 10_000 * 10 ** mockToken.decimals(); // 10,000 tokens
mockToken.mint(ipOwner2, amount2);
vm.startPrank(ipOwner2);
mockToken.approve(address(royaltyModule), amount2);
royaltyModule.payRoyaltyOnBehalf(ipId2, ipOwner2, address(mockToken), amount2);
royaltyPolicyLAP.transferToVault(
ipId2,
newGroupId,
address(mockToken),
(amount2 * revShare) / royaltyModule.maxPercent()
);
royaltyPolicyLAP.transferToVault(ipId2, newGroupId, address(mockToken));
vm.stopPrank();

address[] memory royaltyTokens = new address[](1);
Expand Down
60 changes: 0 additions & 60 deletions test/workflows/RoyaltyWorkflows.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,66 +42,6 @@ contract RoyaltyWorkflowsTest is BaseTest {
_setupCurrencyTokens();
}

function test_RoyaltyWorkflows_transferToVaultAndClaimByTokenBatch() public {
_setupIpGraph();

address[] memory childIpIds = new address[](4);
address[] memory royaltyPolicies = new address[](4);
address[] memory currencyTokens = new address[](4);
uint256[] memory amounts = new uint256[](4);

childIpIds[0] = childIpIdA;
royaltyPolicies[0] = address(royaltyPolicyLRP);
currencyTokens[0] = address(mockTokenA);
amounts[0] = 10 ether;

childIpIds[1] = childIpIdB;
royaltyPolicies[1] = address(royaltyPolicyLRP);
currencyTokens[1] = address(mockTokenA);
amounts[1] = 10 ether;

childIpIds[2] = grandChildIpId;
royaltyPolicies[2] = address(royaltyPolicyLRP);
currencyTokens[2] = address(mockTokenA);
amounts[2] = 1 ether;

childIpIds[3] = childIpIdC;
royaltyPolicies[3] = address(royaltyPolicyLAP);
currencyTokens[3] = address(mockTokenC);
amounts[3] = 10 ether;

uint256 claimerBalanceABefore = mockTokenA.balanceOf(ancestorIpId);
uint256 claimerBalanceCBefore = mockTokenC.balanceOf(ancestorIpId);

uint256[] memory amountsClaimed = royaltyWorkflows.transferToVaultAndClaimByTokenBatch({
ancestorIpId: ancestorIpId,
claimer: ancestorIpId,
childIpIds: childIpIds,
royaltyPolicies: royaltyPolicies,
currencyTokens: currencyTokens,
amounts: amounts
});

uint256 claimerBalanceAAfter = mockTokenA.balanceOf(ancestorIpId);
uint256 claimerBalanceCAfter = mockTokenC.balanceOf(ancestorIpId);

assertEq(amountsClaimed.length, 2); // there are 2 currency tokens
assertEq(claimerBalanceAAfter - claimerBalanceABefore, amountsClaimed[0]);
assertEq(claimerBalanceCAfter - claimerBalanceCBefore, amountsClaimed[1]);
assertEq(
claimerBalanceAAfter - claimerBalanceABefore,
defaultMintingFeeA +
defaultMintingFeeA + // 1000 + 1000 from minting fee of childIpA and childIpB
10 ether + // 10 currency tokens from childIpA transferred to vault
10 ether + // 10 currency tokens from childIpB transferred to vault
1 ether // 1 currency token from grandChildIp transferred to vault
);
assertEq(
claimerBalanceCAfter - claimerBalanceCBefore,
defaultMintingFeeC + 10 ether // 10 currency tokens from childIpC transferred to vault
);
}

function test_RoyaltyWorkflows_claimAllRevenue() public {
_setupIpGraph();

Expand Down
32 changes: 16 additions & 16 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@

"@story-protocol/protocol-core@github:storyprotocol/protocol-core-v1#main":
version "1.1.0"
resolved "https://codeload.github.com/storyprotocol/protocol-core-v1/tar.gz/ed12aec4bfea9127234873dcf06f9f914db068ab"
resolved "https://codeload.github.com/storyprotocol/protocol-core-v1/tar.gz/bd1d8ce8da09c6ea66159c11f9abc4d36fd4f25b"
dependencies:
"@openzeppelin/contracts" "5.0.2"
"@openzeppelin/contracts-upgradeable" "5.0.2"
Expand Down Expand Up @@ -504,9 +504,9 @@
integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==

"@ungap/structured-clone@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
version "1.2.1"
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.1.tgz#28fa185f67daaf7b7a1a8c1d445132c5d979f8bd"
integrity sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==

abbrev@1:
version "1.1.1"
Expand Down Expand Up @@ -888,9 +888,9 @@ death@^1.1.0:
integrity sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==

debug@^4.3.1, debug@^4.3.2, debug@^4.3.5:
version "4.3.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52"
integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==
version "4.4.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a"
integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==
dependencies:
ms "^2.1.3"

Expand Down Expand Up @@ -958,9 +958,9 @@ doctrine@^3.0.0:
esutils "^2.0.2"

dotenv@^16.4.1:
version "16.4.5"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==
version "16.4.7"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.7.tgz#0e20c5b82950140aa99be360a8a5f52335f53c26"
integrity sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==

[email protected]:
version "6.5.4"
Expand Down Expand Up @@ -2084,9 +2084,9 @@ prettier@^2.3.1, prettier@^2.8.3:
integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==

prettier@^3.0.0:
version "3.4.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.4.1.tgz#e211d451d6452db0a291672ca9154bc8c2579f7b"
integrity sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg==
version "3.4.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.4.2.tgz#a5ce1fb522a588bf2b78ca44c6e6fe5aa5a2b13f"
integrity sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==

proto-list@~1.2.1:
version "1.2.4"
Expand Down Expand Up @@ -2468,9 +2468,9 @@ table-layout@^1.0.2:
wordwrapjs "^4.0.0"

table@^6.8.1:
version "6.8.2"
resolved "https://registry.yarnpkg.com/table/-/table-6.8.2.tgz#c5504ccf201213fa227248bdc8c5569716ac6c58"
integrity sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==
version "6.9.0"
resolved "https://registry.yarnpkg.com/table/-/table-6.9.0.tgz#50040afa6264141c7566b3b81d4d82c47a8668f5"
integrity sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==
dependencies:
ajv "^8.0.1"
lodash.truncate "^4.4.2"
Expand Down
Loading