Skip to content

Commit

Permalink
Adds authorization
Browse files Browse the repository at this point in the history
Fixes tests to support the new module enrollment logic

Adds more auth tests
  • Loading branch information
leeren committed Dec 8, 2023
1 parent e8eeee9 commit 5540bb7
Show file tree
Hide file tree
Showing 30 changed files with 661 additions and 131 deletions.
9 changes: 3 additions & 6 deletions contracts/IPAssetRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { IRegistrationModule } from "contracts/interfaces/modules/registration/I
import { IModuleRegistry } from "contracts/interfaces/modules/IModuleRegistry.sol";
import { IIPOrg } from "contracts/interfaces/ip-org/IIPOrg.sol";
import { ModuleRegistryKeys } from "contracts/lib/modules/ModuleRegistryKeys.sol";
import { REGISTRATION_MODULE_KEY } from "contracts/lib/modules/Module.sol";
import { Errors } from "contracts/lib/Errors.sol";

/// @title Global IP Asset Registry
Expand Down Expand Up @@ -41,7 +42,7 @@ contract IPAssetRegistry is IIPAssetRegistry {
/// @notice Restricts calls to the registration module of the IP Asset.
/// TODO(ramarti): Enable IPOrg-specific registration modules to be authorized.
modifier onlyRegistrationModule() {
if (MODULE_REGISTRY.protocolModule(ModuleRegistryKeys.REGISTRATION_MODULE) != msg.sender) {
if (address(MODULE_REGISTRY.protocolModule(REGISTRATION_MODULE_KEY)) != msg.sender) {
revert Errors.Unauthorized();
}
_;
Expand Down Expand Up @@ -70,10 +71,6 @@ contract IPAssetRegistry is IIPAssetRegistry {
bytes32 hash_
) public onlyRegistrationModule returns (uint256 ipAssetId) {

if (MODULE_REGISTRY.protocolModule(ModuleRegistryKeys.REGISTRATION_MODULE) != msg.sender) {
revert Errors.Unauthorized();
}

// Crate a new IP asset with the provided IP attributes.
ipAssetId = ++totalSupply;
uint64 registrationDate = uint64(block.timestamp);
Expand Down Expand Up @@ -129,7 +126,7 @@ contract IPAssetRegistry is IIPAssetRegistry {
/// @notice Returns the current owner of an IP asset.
/// @param ipAssetId_ The id of the IP asset being queried.
function ipAssetOwner(uint256 ipAssetId_) public view returns (address) {
address registrationModule = MODULE_REGISTRY.protocolModule(ModuleRegistryKeys.REGISTRATION_MODULE);
address registrationModule = address(MODULE_REGISTRY.protocolModule(REGISTRATION_MODULE_KEY));
return IRegistrationModule(registrationModule).ownerOf(ipAssetId_);
}

Expand Down
33 changes: 22 additions & 11 deletions contracts/StoryProtocol.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity ^0.8.19;

import { IIPOrgController } from "contracts/interfaces/ip-org/IIPOrgController.sol";
import { IIPOrg } from "contracts/interfaces/ip-org/IIPOrg.sol";
import { Gateway } from "contracts/modules/Gateway.sol";
import { IPOrgParams } from "contracts/lib/IPOrgParams.sol";
import { Errors } from "contracts/lib/Errors.sol";
import { IPOrgParams } from "contracts/lib/IPOrgParams.sol";
Expand All @@ -14,6 +15,11 @@ import { ModuleRegistryKeys } from "contracts/lib/modules/ModuleRegistryKeys.sol
import { Licensing } from "contracts/lib/modules/Licensing.sol";
import { FixedSet } from "contracts/utils/FixedSet.sol";
import { Multicall } from "@openzeppelin/contracts/utils/Multicall.sol";
import { ILicensingModule } from "contracts/interfaces/modules/licensing/ILicensingModule.sol";
import { IRegistrationModule } from "contracts/interfaces/modules/registration/IRegistrationModule.sol";
import { IRelationshipModule } from "contracts/interfaces/modules/relationships/IRelationshipModule.sol";
import { RELATIONSHIP_MODULE, LICENSING_MODULE, REGISTRATION_MODULE } from "contracts/lib/modules/Module.sol";
import { ModuleKey, REGISTRATION_MODULE_KEY, LICENSING_MODULE_KEY, RELATIONSHIP_MODULE_KEY, ModuleDependencies } from "contracts/lib/modules/Module.sol";

/// @title Story Protocol Gateway Contract
/// @notice The Story Protocol contract acts as a global gateway for calling all
Expand All @@ -24,6 +30,11 @@ import { Multicall } from "@openzeppelin/contracts/utils/Multicall.sol";
/// their own frontend contracts (gateways) for IP interaction.
contract StoryProtocol is Multicall {

// Modules which the Story Protocol gateway depends on.
IRegistrationModule public registrationModule;
ILicensingModule public licensingModule;
IRelationshipModule public relationshipModule;

IIPOrgController public immutable IP_ORG_CONTROLLER;
ModuleRegistry public immutable MODULE_REGISTRY;

Expand Down Expand Up @@ -58,7 +69,7 @@ contract StoryProtocol is Multicall {
MODULE_REGISTRY.configure(
IIPOrg(ipOrg_),
msg.sender,
ModuleRegistryKeys.REGISTRATION_MODULE,
REGISTRATION_MODULE,
encodedParams
);
}
Expand All @@ -77,7 +88,7 @@ contract StoryProtocol is Multicall {
MODULE_REGISTRY.configure(
IIPOrg(ipOrg_),
msg.sender,
ModuleRegistryKeys.REGISTRATION_MODULE,
REGISTRATION_MODULE,
encodedParams
);
}
Expand Down Expand Up @@ -118,7 +129,7 @@ contract StoryProtocol is Multicall {
bytes memory result = MODULE_REGISTRY.execute(
IIPOrg(ipOrg_),
msg.sender,
ModuleRegistryKeys.REGISTRATION_MODULE,
REGISTRATION_MODULE,
encodedParams,
preHooksData_,
postHooksData_
Expand Down Expand Up @@ -150,7 +161,7 @@ contract StoryProtocol is Multicall {
MODULE_REGISTRY.execute(
IIPOrg(ipOrg_),
msg.sender,
ModuleRegistryKeys.REGISTRATION_MODULE,
REGISTRATION_MODULE,
encodedParams,
preHooksData_,
postHooksData_
Expand All @@ -168,7 +179,7 @@ contract StoryProtocol is Multicall {
MODULE_REGISTRY.configure(
IIPOrg(params_.ipOrg),
msg.sender,
ModuleRegistryKeys.RELATIONSHIP_MODULE,
RELATIONSHIP_MODULE,
abi.encode(LibRelationship.ADD_REL_TYPE_CONFIG, abi.encode(params_))
);
}
Expand All @@ -180,7 +191,7 @@ contract StoryProtocol is Multicall {
MODULE_REGISTRY.configure(
IIPOrg(ipOrg_),
msg.sender,
ModuleRegistryKeys.RELATIONSHIP_MODULE,
RELATIONSHIP_MODULE,
abi.encode(
LibRelationship.REMOVE_REL_TYPE_CONFIG,
abi.encode(relType)
Expand All @@ -197,7 +208,7 @@ contract StoryProtocol is Multicall {
bytes memory result = MODULE_REGISTRY.execute(
IIPOrg(ipOrg_),
msg.sender,
ModuleRegistryKeys.RELATIONSHIP_MODULE,
RELATIONSHIP_MODULE,
abi.encode(params_),
preHooksData_,
postHooksData_
Expand All @@ -219,7 +230,7 @@ contract StoryProtocol is Multicall {
MODULE_REGISTRY.configure(
IIPOrg(ipOrg_),
msg.sender,
ModuleRegistryKeys.LICENSING_MODULE,
LICENSING_MODULE,
abi.encode(Licensing.LICENSING_FRAMEWORK_CONFIG, abi.encode(config_))
);
}
Expand All @@ -240,7 +251,7 @@ contract StoryProtocol is Multicall {
bytes memory result = MODULE_REGISTRY.execute(
IIPOrg(ipOrg_),
msg.sender,
ModuleRegistryKeys.LICENSING_MODULE,
LICENSING_MODULE,
abi.encode(
Licensing.CREATE_LICENSE,
params
Expand All @@ -261,7 +272,7 @@ contract StoryProtocol is Multicall {
MODULE_REGISTRY.execute(
IIPOrg(ipOrg_),
msg.sender,
ModuleRegistryKeys.LICENSING_MODULE,
LICENSING_MODULE,
abi.encode(
Licensing.ACTIVATE_LICENSE,
abi.encode(licenseId_)
Expand All @@ -283,7 +294,7 @@ contract StoryProtocol is Multicall {
MODULE_REGISTRY.execute(
IIPOrg(ipOrg_),
msg.sender,
ModuleRegistryKeys.LICENSING_MODULE,
LICENSING_MODULE,
abi.encode(
Licensing.LINK_LNFT_TO_IPA,
abi.encode(licenseId_, ipaId_)
Expand Down
2 changes: 1 addition & 1 deletion contracts/access-control/AccessControlSingleton.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: UNLICENSED
// See Story Protocol Alpha Agreement: https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf

pragma solidity ^0.8.13;
pragma solidity ^0.8.19;

import { Errors } from "contracts/lib/Errors.sol";
import { AccessControl } from "contracts/lib/AccessControl.sol";
Expand Down
21 changes: 21 additions & 0 deletions contracts/interfaces/modules/IGateway.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import { ModuleDependencies } from "contracts/lib/modules/Module.sol";

/// @title Module Gateway Interface
/// @notice Interface for a Story Protocol module gateway, which is a contract
/// that may be granted access by the module registry to call module
/// functions declared by the gateway's module dependency set.
interface IGateway {

/// @notice Synchronizes all downstream dependencies via the module registry.
/// @dev This function may only be called by the module registry.
/// @return dependencies The freshly updated dependencies needed by the gateway.
function updateDependencies() external returns (ModuleDependencies memory dependencies);

/// @notice Fetches all module dependencies required by the gateway contract.
/// @return dependencies The dependencies that the gateway requires from the protocol.
function getDependencies() external view returns (ModuleDependencies memory dependencies);

}
53 changes: 47 additions & 6 deletions contracts/interfaces/modules/IModuleRegistry.sol
Original file line number Diff line number Diff line change
@@ -1,21 +1,43 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import { ModuleKey } from "contracts/lib/modules/Module.sol";
import { IGateway } from "contracts/interfaces/modules/IGateway.sol";
import { IModule } from "contracts/interfaces/modules/base/IModule.sol";
import { IIPOrg } from "contracts/interfaces/ip-org/IIPOrg.sol";

/// @title IModuleRegistry
/// @notice Module Registry Interface
interface IModuleRegistry {

/// @notice Emits when a new module is added for a specific IP Org.
/// @notice Emits when a gateway was successfully registered by the protocol
/// for a specific dependency (module type + module function).
/// @param key The identifier of the dependent module type.
/// @param fn The function identifier of the dependent module type.
/// @param gateway The gateway address granted permission to use the dependency.
/// @param grant Whether the gateway was authorized to use the dependency.
event ModuleAuthorizationGranted(
ModuleKey indexed key,
bytes4 fn,
address indexed gateway,
bool grant
);

/// @notice Emits when a brand new module is enrolled to the protocol.
/// @param ipOrg The IP Org to which the module belongs.
/// @param moduleKey The string identifier of the module type that was added.
/// @param module The address of the module.
event ModuleAdded(
address indexed ipOrg,
string moduleKey,
address indexed module
);

/// @notice Emits when a module is removed for an IP Org.
/// @notice Emits when the protocol module for a module type is removed.
/// @param key The identifier of the module type that was added.
/// @param module The address of the removed module
event ModuleRemoved(
address indexed ipOrg,
string moduleKey,
ModuleKey indexed key,
address indexed module
);

Expand Down Expand Up @@ -51,6 +73,25 @@ interface IModuleRegistry {
address indexed hook
);

/// @notice Fetches the latest protocol module bound to a specific key.
function protocolModule(string calldata moduleKey) external view returns (address);
/// @notice Registers a new module of a provided type to Story Protocol.
/// @param key_ The bytes32 type of the module being registered.
/// @param module_ The actual module being registered.
function registerProtocolModule(ModuleKey key_, IModule module_) external;

/// @notice Fetches the protocol module by its string identifier.
/// @param key_ The string module type.
/// @return The module associated with the module key.
function protocolModule(string calldata key_) external view returns (address);

/// @notice Fetches the protocol module bound to a module type.
/// @param key_ The bytes32 module type.
/// @return The module associated with the module key.
function protocolModule(ModuleKey key_) external view returns (address);

/// @notice Checks whether a gateway has permission to call a module function.
/// @param key_ The module type.
/// @param gateway_ The gateway which has the module as a dependency.
/// @param fn_ The module function whose access is being checked for.
function isAuthorized(ModuleKey key_, IGateway gateway_, bytes4 fn_) external view returns (bool);

}
6 changes: 5 additions & 1 deletion contracts/interfaces/modules/base/IModule.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import { IModule } from "./IModule.sol";
import { IIPOrg } from "contracts/interfaces/ip-org/IIPOrg.sol";
import { ModuleKey } from "contracts/lib/modules/Module.sol";

/// @title IModule
/// @notice Interface for a Story Protocol Module, building block of the protocol functionality.
Expand All @@ -14,6 +14,10 @@ interface IModule {
/// Module execution failed.
event RequestFailed(address indexed sender, string reason);

/// @notice Gets the protocol-wide key associated with the module.
/// @return The bytes32 identifier of the module.
function moduleKey() external pure returns (ModuleKey);

/// @notice Main execution entrypoint.
/// @dev It will verify params, execute pre action hooks, perform the action,
/// execute post action hooks and emit the RequestCompleted event, plus returning the result.
Expand Down
9 changes: 9 additions & 0 deletions contracts/interfaces/modules/licensing/ILicensingModule.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import { IModule } from "contracts/interfaces/modules/base/IModule.sol";

/// @title Licensing Module Interface
/// @notice Interface for the licensing module
/// TODO(ramarti): Fill this in.
interface ILicensingModule is IModule {}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
pragma solidity ^0.8.19;

import { Registration } from "contracts/lib/modules/Registration.sol";
import { IIPOrg } from "contracts/interfaces/ip-org/IIPOrg.sol";
import { IModule } from "contracts/interfaces/modules/base/IModule.sol";

/// @title IRegistrationModule
interface IRegistrationModule {
interface IRegistrationModule is IModule {

/// @notice Emits when an IPOrg updates metadata associated with its IPA.
/// @param ipOrg The address of the IP Org whose metadata was updated.
Expand Down Expand Up @@ -76,4 +78,5 @@ interface IRegistrationModule {

/// @notice Returns true if the index for an IP Org asset type is supported.
function isValidIpOrgAssetType(address ipOrg_, uint8 index) external view returns (bool);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
pragma solidity ^0.8.13;

import { LibRelationship } from "contracts/lib/modules/LibRelationship.sol";
import { IModule } from "contracts/interfaces/modules/base/IModule.sol";

/// @title IRelationshipModule
/// @notice Interface for the RelationshipModule.
interface IRelationshipModule {
interface IRelationshipModule is IModule {

/// Emitted with a new Relationship Type definitions is created
event RelationshipTypeSet(
// Short string naming the type
Expand Down
10 changes: 5 additions & 5 deletions contracts/ip-org/IPOrg.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { IPOrgParams } from "contracts/lib/IPOrgParams.sol";
import { ERC721Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import { IERC165Upgradeable } from "@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol";
import { IPAssetRegistry } from "contracts/IPAssetRegistry.sol";
import { ModuleRegistryKeys } from "contracts/lib/modules/ModuleRegistryKeys.sol";
import { REGISTRATION_MODULE_KEY } from "contracts/lib/modules/Module.sol";
import { Errors } from "contracts/lib/Errors.sol";

/// @title IP Organization Contract
Expand Down Expand Up @@ -42,7 +42,7 @@ contract IPOrg is

/// @notice Restricts calls to being through the registration module.
modifier onlyRegistrationModule() {
if (IModuleRegistry(MODULE_REGISTRY).protocolModule(ModuleRegistryKeys.REGISTRATION_MODULE) != msg.sender) {
if (address(MODULE_REGISTRY.protocolModule(REGISTRATION_MODULE_KEY)) != msg.sender) {
revert Errors.Unauthorized();
}
_;
Expand Down Expand Up @@ -74,21 +74,21 @@ contract IPOrg is
function tokenURI(
uint256 tokenId_
) public view override returns (string memory) {
address registrationModule = IModuleRegistry(MODULE_REGISTRY).protocolModule(ModuleRegistryKeys.REGISTRATION_MODULE);
address registrationModule = address(IModuleRegistry(MODULE_REGISTRY).protocolModule(REGISTRATION_MODULE_KEY));
return IRegistrationModule(registrationModule).tokenURI(address(this), tokenId_, ipOrgAssetType(tokenId_));
}

/// @notice Retrieves the contract URI for the IP Org collection.
function contractURI() public view override returns (string memory) {
address registrationModule = IModuleRegistry(MODULE_REGISTRY).protocolModule(ModuleRegistryKeys.REGISTRATION_MODULE);
address registrationModule = address(IModuleRegistry(MODULE_REGISTRY).protocolModule(REGISTRATION_MODULE_KEY));
return IRegistrationModule(registrationModule).contractURI(address(this));
}

/// @notice Gets the global IP asset id associated with this IP Org asset.
/// @param id The local id of the IP Org wrapped IP asset.
/// @return The global identifier of the IP asset.
function ipAssetId(uint256 id) public returns (uint256) {
address registrationModule = MODULE_REGISTRY.protocolModule(ModuleRegistryKeys.REGISTRATION_MODULE);
address registrationModule = address(MODULE_REGISTRY.protocolModule(REGISTRATION_MODULE_KEY));
return IRegistrationModule(registrationModule).ipAssetId(address(this), id);
}

Expand Down
3 changes: 2 additions & 1 deletion contracts/ip-org/IPOrgController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { IIPOrgController } from "contracts/interfaces/ip-org/IIPOrgController.s
import { IIPOrg } from "contracts/interfaces/ip-org/IIPOrg.sol";
import { IPOrg } from "contracts/ip-org/IPOrg.sol";
import { AccessControl } from "contracts/lib/AccessControl.sol";
import { REGISTRATION_MODULE } from "contracts/lib/modules/Module.sol";

/// @title IP Org Controller Contract
/// @notice The IP Org Controller is the protocol-wide factory contract for creating
Expand Down Expand Up @@ -184,7 +185,7 @@ contract IPOrgController is
ModuleRegistry(MODULE_REGISTRY).configure(
IIPOrg(ipOrg_),
address(this),
ModuleRegistryKeys.REGISTRATION_MODULE,
REGISTRATION_MODULE,
encodedParams
);

Expand Down
Loading

0 comments on commit 5540bb7

Please sign in to comment.