StoreFactory
Inherits: Ownable, IStoreFactory
Title: StoreFactory
Factory for the two per-user DotNS store types, sharing one factory contract and two beacons. @dev Each user may acquire AT MOST two stores, ever:
- a
LabelStore, deployed viadeployLabelStoreForby a protocol-registered caller during registration; and - a
UserStore, claimed viaclaimUserStoreby the user themselves. Both areBeaconProxyinstances pointing at their respectiveUpgradeableBeacon. The factory owns both beacons so the factory owner can upgrade implementations for every proxy atomically. Neither per-user mapping is ever transferred, reassigned, or overwritten after the first write; bindings are permanent.
Note: security-contact: admin@parity.io
Constants
labelStoreBeacon
Beacon backing every LabelStore proxy.
Public getter name is interface-constrained by @custom:contract IStoreFactory.
address public immutable override labelStoreBeacon
userStoreBeacon
Beacon backing every UserStore proxy.
Public getter name is interface-constrained by @custom:contract IStoreFactory.
address public immutable override userStoreBeacon
protocolRegistry
Protocol registry used to authorise deployLabelStoreFor callers.
Public getter name is interface-constrained by @custom:contract IStoreFactory.
address public immutable override protocolRegistry
State Variables
_labelStores
user => their permanent LabelStore. Set once per user, forever.
mapping(address user => address store) private _labelStores
_userStores
user => their permanent UserStore. Set once per user, forever.
mapping(address user => address store) private _userStores
_labelStoreList
Insertion-order list of every LabelStore proxy ever deployed. Append-only.
address[] private _labelStoreList
_userStoreList
Insertion-order list of every UserStore proxy ever claimed. Append-only.
address[] private _userStoreList
Functions
onlyOwnerOrProtocol
Restricts deployLabelStoreFor to the owner or any protocol-registered caller.
modifier onlyOwnerOrProtocol() ;
constructor
Deploys the factory together with both store implementations and beacons.
A single new StoreFactory(protocolRegistry, owner) call wires everything:
- Deploys a fresh
LabelStoreimplementation. - Deploys a fresh
UserStoreimplementation. - Constructs both
UpgradeableBeaconinstances, owned byaddress(this)soupgrade*Implementationcan delegate tobeacon.upgradeTo. Keeping the implementation deployments inside the constructor removes a class of operator error: there is no "did I deploy the implementation first?" step and no way to pass the wrong implementation address.protocolRegistry_must be non-zero, otherwise @custom:reverts InvalidProtocolRegistry.
Implementations and beacons are deployed inline so a single factory address fully describes the store topology, removing a class of operator error around mismatched beacons.
constructor(address protocolRegistry_, address owner_) Ownable(owner_);
Parameters
| Name | Type | Description |
|---|---|---|
protocolRegistry_ | address | The protocol registry for writer auth on label stores. |
owner_ | address | Account that owns this factory and can upgrade store implementations. |
deployLabelStoreFor
Deploys a LabelStore beacon-proxy bound to user.
Callable by the factory owner or any address currently registered in the protocol
registry; any other caller @custom:reverts NotAuthorised. user must be non-zero,
otherwise @custom:reverts InvalidUser. The user must not already have a
LabelStore, otherwise @custom:reverts AlreadyDeployed. After deployment the
freshly initialised proxy must report user as its owner, otherwise
Notes:
-
reverts: ImplementationBindingMismatch. Emits
-
emits: LabelStoreDeployed on success.
function deployLabelStoreFor(address user)
external
override
onlyOwnerOrProtocol
returns (address store);
Parameters
| Name | Type | Description |
|---|---|---|
user | address | The user the store is bound to forever. |
Returns
| Name | Type | Description |
|---|---|---|
store | address | The deployed store address. |
getLabelStore
Returns the LabelStore address bound to user, or the zero address if none.
function getLabelStore(address user) external view override returns (address store);
Parameters
| Name | Type | Description |
|---|---|---|
user | address | The user to look up. |
Returns
| Name | Type | Description |
|---|---|---|
store | address | The bound store address, or zero. |
getLabelStoreCount
Returns the total number of LabelStore proxies ever deployed.
function getLabelStoreCount() external view override returns (uint256 count);
Returns
| Name | Type | Description |
|---|---|---|
count | uint256 | Length of the deployment list. |
getLabelStores
Paginated enumeration over every LabelStore proxy ever deployed.
Insertion order of deployLabelStoreFor calls. offset >= getLabelStoreCount()
returns an empty array; result length is min(limit, count - offset).
function getLabelStores(
uint256 offset,
uint256 limit
)
external
view
override
returns (address[] memory stores);
Parameters
| Name | Type | Description |
|---|---|---|
offset | uint256 | Start index. |
limit | uint256 | Maximum entries to return. |
Returns
| Name | Type | Description |
|---|---|---|
stores | address[] | Slice of label-store addresses. |
upgradeLabelStoreImplementation
Upgrades the LabelStore implementation for every existing and future proxy.
Callable by the factory owner only, otherwise
Notes:
-
reverts: OwnableUnauthorizedAccount.
newImplementationmust be non-zero, otherwise @custom:reverts InvalidImplementation. The candidate is sentinel-probed by callingILabelStore.protocolRegistryon it before the beacon is rotated; if the address does not implement that selector the probe reverts and the upgrade does not land (deliberate fail-fast guard, no named error). Delegates toUpgradeableBeacon.upgradeToand emits -
emits: LabelStoreImplementationUpgraded on success.
function upgradeLabelStoreImplementation(address newImplementation)
external
override
onlyOwner;
Parameters
| Name | Type | Description |
|---|---|---|
newImplementation | address | The new implementation address. |
claimUserStore
Caller claims their UserStore beacon-proxy.
Self-claim only; _owner on the resulting store is always msg.sender,
regardless of who pays gas. One store per caller, forever: a caller who already
has a UserStore @custom:reverts AlreadyDeployed. After deployment the freshly
initialised proxy must report msg.sender as its owner, otherwise
Notes:
-
reverts: ImplementationBindingMismatch. Emits
-
emits: UserStoreClaimed on success.
function claimUserStore() external override returns (address store);
Returns
| Name | Type | Description |
|---|---|---|
store | address | The deployed store address. |
getUserStore
Returns the UserStore address bound to user, or the zero address if none.
function getUserStore(address user) external view override returns (address store);
Parameters
| Name | Type | Description |
|---|---|---|
user | address | The user to look up. |
Returns
| Name | Type | Description |
|---|---|---|
store | address | The bound store address, or zero. |
getUserStoreCount
Returns the total number of UserStore proxies ever claimed.
function getUserStoreCount() external view override returns (uint256 count);
Returns
| Name | Type | Description |
|---|---|---|
count | uint256 | Length of the claim list. |
getUserStores
Paginated enumeration over every UserStore proxy ever claimed.
Insertion order of claimUserStore calls. offset >= getUserStoreCount()
returns an empty array; result length is min(limit, count - offset).
function getUserStores(
uint256 offset,
uint256 limit
)
external
view
override
returns (address[] memory stores);
Parameters
| Name | Type | Description |
|---|---|---|
offset | uint256 | Start index. |
limit | uint256 | Maximum entries to return. |
Returns
| Name | Type | Description |
|---|---|---|
stores | address[] | Slice of user-store addresses. |
upgradeUserStoreImplementation
Upgrades the UserStore implementation for every existing and future proxy.
Callable by the factory owner only, otherwise
Notes:
-
reverts: OwnableUnauthorizedAccount.
newImplementationmust be non-zero, otherwise @custom:reverts InvalidImplementation. The candidate is sentinel-probed by callingIUserStore.getKeyCounton it before the beacon is rotated; if the address does not implement that selector the probe reverts and the upgrade does not land (deliberate fail-fast guard, no named error). Delegates toUpgradeableBeacon.upgradeToand emits -
emits: UserStoreImplementationUpgraded on success.
function upgradeUserStoreImplementation(address newImplementation) external override onlyOwner;
Parameters
| Name | Type | Description |
|---|---|---|
newImplementation | address | The new implementation address. |
version
Returns implementation version.
function version() external pure virtual returns (string memory versionString);
Returns
| Name | Type | Description |
|---|---|---|
versionString | string | Current version string. |
_onlyOwnerOrProtocol
Internal authorisation check deferred from the onlyOwnerOrProtocol modifier.
function _onlyOwnerOrProtocol() internal view;
_paginateAddresses
Shared pagination helper used by getLabelStores and getUserStores.
Single canonical slicer so both enumerations bound-check and copy identically.
function _paginateAddresses(
address[] storage source,
uint256 offset,
uint256 limit
)
internal
view
returns (address[] memory slice);
Parameters
| Name | Type | Description |
|---|---|---|
source | address[] | Storage array to slice. |
offset | uint256 | Start index. |
limit | uint256 | Maximum entries to return. |
Returns
| Name | Type | Description |
|---|---|---|
slice | address[] | Result slice; empty when offset >= source.length. |