RAIModuleFactory
Inherits: Ownable2Step
Title: RAIModuleFactory
Deploys and manages isolated RAI modules (Subscription, Credit, etc.)
Uses uint256 module IDs for infinite expansion without factory redeployment. This enables a plug-and-play architecture where new module types can be added by simply deploying an implementation and calling setImplementation(). Module ID System:
- 0 = SUBSCRIPTION
- 1 = CREDIT
- 2+ = Future modules (Usage, Tiered, Pay-per-View, etc.) Plug-and-Play Flow:
- Deploy new module implementation (e.g., UsageModule)
- Owner calls setImplementation(moduleId, implementationAddress)
- Merchants can immediately deploy modules via deployModule(moduleId)
State Variables
paymentProcessor
Global PaymentProcessor used by all merchant modules
address public immutable paymentProcessor
implementations
Mapping: moduleId => implementation logic address
mapping(uint256 => address) public implementations
moduleOf
Mapping: merchant => moduleId => their deployed clone
mapping(address => mapping(uint256 => address)) public moduleOf
merchantRegistry
Optional MerchantRegistry address for profile verification
address public merchantRegistry
requireMerchantProfile
Whether to require merchant profile registration before deployment
bool public requireMerchantProfile
Functions
constructor
constructor(address _paymentProcessor) Ownable(msg.sender);
setImplementation
Sets the implementation logic for a specific module type.
Can be called multiple times to update implementations (e.g., for upgrades). This enables infinite expansion - new module types can be added without redeploying the factory.
function setImplementation(uint256 moduleId, address impl) external onlyOwner;
Parameters
| Name | Type | Description |
|---|---|---|
moduleId | uint256 | The module ID (0 = SUBSCRIPTION, 1 = CREDIT, 2+ = future modules) |
impl | address | The address of the logic contract |
setMerchantRegistry
Sets the MerchantRegistry address (optional).
Can be set to address(0) to disable merchant registry checks.
function setMerchantRegistry(address _merchantRegistry) external onlyOwner;
Parameters
| Name | Type | Description |
|---|---|---|
_merchantRegistry | address | The address of the MerchantRegistry contract |
setRequireMerchantProfile
Sets whether merchant profile registration is required.
Only effective if merchantRegistry is set to a non-zero address.
function setRequireMerchantProfile(bool _requireMerchantProfile) external onlyOwner;
Parameters
| Name | Type | Description |
|---|---|---|
_requireMerchantProfile | bool | Whether to require merchant profile registration |
deployModule
Deploys a module of a specific type for the merchant.
Steps:
- Validate implementation is set
- Enforce one module per merchant per module type
- Clone the implementation (EIP-1167)
- Initialize with (merchant, paymentProcessor)
- Register with PaymentProcessor
- Store mapping
function deployModule(uint256 moduleId) external returns (address module);
Parameters
| Name | Type | Description |
|---|---|---|
moduleId | uint256 | The type of module to deploy (0 = SUBSCRIPTION, 1 = CREDIT, etc.) |
Returns
| Name | Type | Description |
|---|---|---|
module | address | The address of the new proxy |
getModule
Returns the module belonging to a merchant for a specific module type
function getModule(address merchant, uint256 moduleId) external view returns (address);
Parameters
| Name | Type | Description |
|---|---|---|
merchant | address | Merchant address |
moduleId | uint256 | Module type ID |
Returns
| Name | Type | Description |
|---|---|---|
<none> | address | The module address, or address(0) if not deployed |
Events
ModuleCreated
event ModuleCreated(address indexed merchant, address indexed module, uint256 indexed moduleId);
ImplementationUpdated
event ImplementationUpdated(uint256 indexed moduleId, address indexed implementation);
MerchantRegistryUpdated
event MerchantRegistryUpdated(address indexed merchantRegistry);
RequireMerchantProfileUpdated
event RequireMerchantProfileUpdated(bool requireMerchantProfile);
Errors
InvalidAddress
error InvalidAddress();
NotAContract
error NotAContract();
ModuleAlreadyExists
error ModuleAlreadyExists();
ImplementationNotSet
error ImplementationNotSet();
MerchantNotRegistered
error MerchantNotRegistered();