Skip to content

Commit

Permalink
Upgrade beacon through RoyaltyPolicyLAP (#88)
Browse files Browse the repository at this point in the history
* upgrade beacon via RoyaltyPolicyLAP

* lint
  • Loading branch information
Ramarti authored Apr 14, 2024
1 parent 08434de commit a997c50
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 3 deletions.
11 changes: 11 additions & 0 deletions contracts/modules/royalty/policies/RoyaltyPolicyLAP.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s
import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { BeaconProxy } from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
import { UpgradeableBeacon } from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
// solhint-disable-next-line max-line-length
import { AccessManagedUpgradeable } from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol";

Expand Down Expand Up @@ -97,6 +98,16 @@ contract RoyaltyPolicyLAP is IRoyaltyPolicyLAP, AccessManagedUpgradeable, Reentr
$.ipRoyaltyVaultBeacon = beacon;
}

/// @dev Upgrades the ip royalty vault beacon
/// @dev Enforced to be only callable by the upgrader admin
/// @param newVault The new ip royalty vault beacon address
function upgradeVaults(address newVault) public restricted {
// UpgradeableBeacon already checks for newImplementation.bytecode.length > 0,
// no need to check for zero address
RoyaltyPolicyLAPStorage storage $ = _getRoyaltyPolicyLAPStorage();
UpgradeableBeacon($.ipRoyaltyVaultBeacon).upgradeTo(newVault);
}

/// @notice Executes royalty related logic on minting a license
/// @dev Enforced to be only callable by RoyaltyModule
/// @param ipId The ipId whose license is being minted (licensor)
Expand Down
16 changes: 14 additions & 2 deletions script/foundry/utils/DeployHelper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ contract DeployHelper is Script, BroadcastManager, JsonDeploymentHandler, Storag
(bool multisigAdmin, ) = protocolAccessManager.hasRole(ProtocolAdmin.PROTOCOL_ADMIN_ROLE, multisig);
(bool multisigUpgrader, ) = protocolAccessManager.hasRole(ProtocolAdmin.UPGRADER_ROLE, multisig);

if (address(royaltyPolicyLAP) != ipRoyaltyVaultBeacon.owner()) {
revert RoleConfigError("RoyaltyPolicyLAP is not owner of IpRoyaltyVaultBeacon");
}

if (!multisigAdmin || !multisigUpgrader) {
revert RoleConfigError("Multisig roles not granted");
}
Expand Down Expand Up @@ -340,7 +344,8 @@ contract DeployHelper is Script, BroadcastManager, JsonDeploymentHandler, Storag
_postdeploy("IpRoyaltyVaultImpl", address(ipRoyaltyVaultImpl));

_predeploy("IpRoyaltyVaultBeacon");
ipRoyaltyVaultBeacon = new UpgradeableBeacon(address(ipRoyaltyVaultImpl), address(protocolAccessManager));
// Transfer Ownership to RoyaltyPolicyLAP later
ipRoyaltyVaultBeacon = new UpgradeableBeacon(address(ipRoyaltyVaultImpl), deployer);
_postdeploy("IpRoyaltyVaultBeacon", address(ipRoyaltyVaultBeacon));

_predeploy("CoreMetadataModule");
Expand Down Expand Up @@ -396,6 +401,7 @@ contract DeployHelper is Script, BroadcastManager, JsonDeploymentHandler, Storag
royaltyModule.whitelistRoyaltyToken(address(erc20), true);
royaltyPolicyLAP.setSnapshotInterval(7 days);
royaltyPolicyLAP.setIpRoyaltyVaultBeacon(address(ipRoyaltyVaultBeacon));
ipRoyaltyVaultBeacon.transferOwnership(address(royaltyPolicyLAP));

// Dispute Module and SP Dispute Policy
address arbitrationRelayer = relayer;
Expand Down Expand Up @@ -429,11 +435,17 @@ contract DeployHelper is Script, BroadcastManager, JsonDeploymentHandler, Storag
);
protocolAccessManager.setTargetFunctionRole(address(licensingModule), selectors, ProtocolAdmin.UPGRADER_ROLE);
protocolAccessManager.setTargetFunctionRole(address(royaltyModule), selectors, ProtocolAdmin.UPGRADER_ROLE);
protocolAccessManager.setTargetFunctionRole(address(royaltyPolicyLAP), selectors, ProtocolAdmin.UPGRADER_ROLE);
protocolAccessManager.setTargetFunctionRole(address(licenseRegistry), selectors, ProtocolAdmin.UPGRADER_ROLE);
protocolAccessManager.setTargetFunctionRole(address(moduleRegistry), selectors, ProtocolAdmin.UPGRADER_ROLE);
protocolAccessManager.setTargetFunctionRole(address(ipAssetRegistry), selectors, ProtocolAdmin.UPGRADER_ROLE);

// Royalty and Upgrade Beacon
// Owner of the beacon is the RoyaltyPolicyLAP
selectors = new bytes4[](2);
selectors[0] = RoyaltyPolicyLAP.upgradeVaults.selector;
selectors[1] = UUPSUpgradeable.upgradeToAndCall.selector;
protocolAccessManager.setTargetFunctionRole(address(royaltyPolicyLAP), selectors, ProtocolAdmin.UPGRADER_ROLE);

///////// Role Granting /////////
protocolAccessManager.grantRole(ProtocolAdmin.UPGRADER_ROLE, multisig, upgraderExecDelay);
protocolAccessManager.grantRole(ProtocolAdmin.PROTOCOL_ADMIN_ROLE, multisig, 0);
Expand Down
2 changes: 1 addition & 1 deletion script/foundry/utils/upgrades/ERC7201Helper.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { console2 } from "forge-std/console2.sol";
contract ERC7201HelperScript is Script {

string constant NAMESPACE = "story-protocol";
string constant CONTRACT_NAME = "IPAssetRegistry";
string constant CONTRACT_NAME = "MockIPRoyaltyVaultV2";

function run() external {
bytes memory erc7201Key = abi.encodePacked(NAMESPACE, ".", CONTRACT_NAME);
Expand Down
36 changes: 36 additions & 0 deletions test/foundry/mocks/module/MockIpRoyaltyVaultV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { IpRoyaltyVault } from "contracts/modules/royalty/policies/IpRoyaltyVault.sol";

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

contract MockIpRoyaltyVaultV2 is IpRoyaltyVault {
/// @dev Storage structure for the MockIPRoyaltyVaultV2
/// @custom:storage-location erc7201:story-protocol.MockIPRoyaltyVaultV2
struct MockIPRoyaltyVaultV2Storage {
string newState;
}

// keccak256(abi.encode(uint256(keccak256("story-protocol.MockIPRoyaltyVaultV2")) - 1)) & ~bytes32(uint256(0xff));
bytes32 private constant MockIPRoyaltyVaultV2StorageLocation =
0x2942176f94974e015a9b06f79a3a2280d18f1872591c134ba237fa184e378300;

/// @custom:oz-upgrades-unsafe-allow constructor
constructor(address royaltyPolicyLAP, address disputeModule) IpRoyaltyVault(royaltyPolicyLAP, disputeModule) {
_disableInitializers();
}

function set(string calldata value) external {
_getMockIPRoyaltyVaultV2Storage().newState = value;
}

function get() external view returns (string memory) {
return _getMockIPRoyaltyVaultV2Storage().newState;
}

/// @dev Returns the storage struct of MockIPRoyaltyVaultV2.
function _getMockIPRoyaltyVaultV2Storage() private pure returns (MockIPRoyaltyVaultV2Storage storage $) {
assembly {
$.slot := MockIPRoyaltyVaultV2StorageLocation
}
}
}
40 changes: 40 additions & 0 deletions test/foundry/upgrades/IPRoyaltyVaults.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import { ProtocolAdmin } from "contracts/lib/ProtocolAdmin.sol";
import { RoyaltyPolicyLAP } from "contracts/modules/royalty/policies/RoyaltyPolicyLAP.sol";

import { BaseTest } from "../utils/BaseTest.t.sol";

import { MockIpRoyaltyVaultV2 } from "../mocks/module/MockIpRoyaltyVaultV2.sol";

contract IPRoyaltyVaults is BaseTest {
function setUp() public override {
super.setUp();
vm.prank(u.admin);
protocolAccessManager.grantRole(ProtocolAdmin.UPGRADER_ROLE, u.alice, upgraderExecDelay);
}

function test_upgradeVaults() public {
address newVault = address(new MockIpRoyaltyVaultV2(address(royaltyPolicyLAP), address(disputeModule)));
(bool immediate, uint32 delay) = protocolAccessManager.canCall(
u.alice,
address(royaltyPolicyLAP),
RoyaltyPolicyLAP.upgradeVaults.selector
);
assertFalse(immediate);
assertEq(delay, 600);
vm.prank(u.alice);
(bytes32 operationId, uint32 nonce) = protocolAccessManager.schedule(
address(royaltyPolicyLAP),
abi.encodeCall(RoyaltyPolicyLAP.upgradeVaults, (newVault)),
0 // earliest time possible, upgraderExecDelay
);
vm.warp(upgraderExecDelay + 1);

vm.prank(u.alice);
royaltyPolicyLAP.upgradeVaults(newVault);

assertEq(ipRoyaltyVaultBeacon.implementation(), newVault);
}
}

0 comments on commit a997c50

Please sign in to comment.