WalletFactory Documentation
Overview
WalletFactory deploys entity-scoped wallet proxies using EBSI template infrastructure.
Its role is intentionally limited to deployment-time concerns:
- checks entity-manager authorization in
EntityRegistry, - checks entity status,
- resolves a template by
walletType, - forwards caller-provided
initDatato the proxy deployment flow.
The factory is generic with respect to wallet initialization shape. It does not build CompanyWallet init payloads internally.
Prerequisites
- Proxy is initialized with non-zero
entityRegistryandowner. entityRegistrymust implementIEntityRegistry.- Proxy templates are configured for each supported
walletType. - Caller is an entity manager for
params.entityId. - Registered manager accounts must remain enabled and linked to
params.entityId; disabling, removing, or transferring the account invalidates stale manager authority inEntityRegistry. - Entity for
params.entityIdisENABLED. params.initDatais non-empty and valid for the selected wallet template.
Contract Architecture
WalletFactory inherits:
IWalletFactoryWalletFactoryStorageProxyDeployerReentrancyGuardInitializable
Key architecture decisions:
- Deployment authorization is entity-scoped through
EntityRegistry. - Runtime wallet authorization is not handled by the factory.
- Initialization is fully caller-driven through opaque
initData. - Wallet type resolution is a thin mapping from
walletType -> templateId. - Shared proxy deployment behavior comes from
ProxyDeployer; its factory, registry, DID, and template config state is stored through ERC-7201 namespaced storage. - The factory itself follows the repository-standard implementation + ERC1967 proxy pattern.
createWallet(...)uses the inherited unsalted_deployProxy(...)path. It does not callcomputeProxyAddress(...)or_deployProxyWithSalt(...), so the factory does not provide a deterministic address guarantee from(entityId, walletType, initData).
Authorization Model
Entity manager
Can:
- call
createWallet(...)for an entity they manage.
Managers may be unregistered EOAs during first-wallet onboarding. Once a manager address is registered as an entity account, its manager authority follows that account lifecycle in EntityRegistry; lifecycle changes require explicit manager reassignment before the address can deploy more wallets.
Factory owner
Can:
- assign or update template mappings via
setWalletTemplateForType(...), - manage inherited
ProxyDeployerowner-only configuration.
Core Functions
initialize(address entityRegistry_, address owner_)
Initializes the factory proxy and stores the EntityRegistry reference.
Prerequisites:
entityRegistry_ != address(0)owner_ != address(0)entityRegistry_implementsIEntityRegistry
Parameters:
entityRegistry_: Entity registry used for deployment authorization.owner_: Factory owner.
Events:
EntityRegistrySet(address entityRegistry)
createWallet(CreateWalletParams calldata params)
Deploys a wallet proxy for an enabled entity.
Prerequisites:
- Caller is an entity manager for
params.entityId - If caller is registered as an account, it has not been disabled, removed, or transferred away from
params.entityIdsince its manager assignment - Entity status is
ENABLED params.walletTypeis configuredparams.initData.length != 0
Parameters:
params.entityId: Entity for which the wallet is created.params.walletType: Wallet type identifier used to resolve the template.params.initData: Wallet-specific initialization payload forwarded to the proxy.
Returns:
address: Deployed wallet proxy address.
Important Notes:
- Wallet addresses are not precomputed by
createWallet(...). Address prediction helpers onProxyDeployerapply to the salted deployment helper path, which this function does not use.
Events:
WalletCreated(bytes32 entityId, address wallet, bytes32 walletType, address caller)
Errors:
WalletFactory__NotEntityManager(address,bytes32): caller is not authorized for the entity.WalletFactory__EntityNotEnabled(bytes32): entity is not enabled.WalletFactory__InitDataEmpty(): init payload is empty.ER__CompanyWalletTypeIdZero(): wallet type is zero.ER__CompanyWalletTypeNotConfigured(bytes32): no template is configured for the wallet type.ER__CompanyWalletAddressZero(): proxy deployment returned zero address.
Notes:
- The entity manager is responsible for providing the correct wallet owner within
initData. Owner validation is therefore not performed by the factory orEntityRegistry. It is intentional business logic delegated to the entity. - Owner choice must match the intended operational mode. For broker or custodian fleets, see the
security operational model, especially Root-Controlled Subwallet Mode and its controls for nested wallet ownership. - The factory does not parse or validate the contents of
initData, including wallet-specific dependencies such as thePolicyRegistryaddress used by aCompanyWalletinitializer. - For the standard DEUSS-managed
CompanyWalletflow, operators are expected to use the protocolPolicyRegistry; this is an operational/template configuration responsibility, not a factory-level invariant. - Post-deployment account registration in
EntityRegistryremains a separate flow.WalletCreatedrecords which entity manager created the proxy, but it does not automatically link the new wallet account to that entity.
Sequence Diagram:
setWalletTemplateForType(bytes32 walletType, string calldata name, string calldata version)
Maps a wallet type to a proxy template.
Prerequisites:
- Caller is factory owner.
walletType != bytes32(0).- Template exists or can be created through inherited template config flow.
Parameters:
walletType: Logical wallet type identifier.name: Template contract name.version: Template version.
Events:
WalletTemplateForTypeSet(bytes32 indexed walletType, bytes32 indexed templateId, string name, string version)
Notes:
- If the template config is not active yet, the factory adds it through
ProxyDeployer.
Sequence Diagram:
getWalletTemplateIdForType(bytes32 walletType)
Returns the configured template id for a wallet type.
entityRegistry()
Returns the EntityRegistry used for deployment authorization.
Deployment Flow
WalletFactoryDeployerdeploys theWalletFactoryimplementation.WalletFactoryDeployerdeploys an ERC1967 proxy and callsinitialize(entityRegistry, governance).- Manager calls
createWallet(...)on the factory proxy. - Factory checks
EntityRegistry.isEntityManager(entityId, msg.sender). - Factory checks
EntityRegistry.getEntityStatus(entityId) == ENABLED. - Factory resolves
templateIdfromwalletType. - Factory forwards
initDatainto_deployProxy(...). - Factory emits
WalletCreated(...).
createWallet(...) does not accept or derive a salt. Operators should use the emitted WalletCreated(...) event or transaction return value as the canonical wallet address source.
Trust Boundary
WalletFactoryis trusted only for deployment orchestration.EntityRegistryis trusted for entity-manager and entity-status checks.- Proxy template configuration inherited from
ProxyDeployerremains a factory-owner responsibility. - Wallet-specific initialization correctness is delegated to the caller and selected template.
- Because initialization is opaque, adding stricter validation for known wallet templates would require type-specific factory logic or a separate deployment helper.