Onchain Cap Table Overview
Here's where you'll find both the factory and the cap table implementation:
- CapTable.sol
- CapTableFactory.sol
Ownership & Role Model
The protocol uses a three-tier access model for cap table management:
- ADMIN_ROLE — the asset manager's wallet. This is the issuer who owns the cap table. They mint onchain cap tables, grant/revoke roles, and make governance decisions. When a cap table is created via the factory,
msg.senderreceives ADMIN. - OPERATOR_ROLE — Transfer Agent Protocol's server wallet. Issues stock, transfers it, cancels it, re-issues it, manages shareholders, creates stock classes and stakeholders. All day-to-day cap table operations. Admins are implicitly operators.
- Factory owner — the protocol deployer. Controls the
UpgradeableBeaconand can upgrade theCapTableimplementation for all proxies viaupdateCapTableImplementation(). Has no access to individual cap tables.
This separation means: asset managers own their cap tables, the protocol operates them, and the protocol deployer can ship upgrades to all cap tables via the beacon pattern.
createCapTable accepts an operator address so the protocol server can receive OPERATOR_ROLE in a single transaction during creation. Pass address(0) to skip the operator grant.
UpgradeableBeacon Pattern
The factory uses OpenZeppelin's UpgradeableBeacon proxy pattern:
- Each cap table created via
createCapTableis aBeaconProxypointing to a shared beacon - The beacon stores the address of the current
CapTableimplementation - The factory owner can call
updateCapTableImplementation(address newImpl)to upgrade all existing cap tables at once — no per-proxy migration needed - Individual cap table admins/operators cannot change their implementation — only the factory owner can
This means the protocol can ship contract upgrades to every cap table in a single transaction.
Access Control
Functions gated by onlyOperator (server wallet + admins):
createStockClass,createStakeholder,createStockLegendTemplate— structural setupissueStock,transferStock,repurchaseStock,retractStockIssuance,reissueStock,cancelStock— stock lifecycleaddWalletToStakeholder,removeWalletFromStakeholder— wallet managementmintActivePositions,mintSharesAuthorized— initial seedingadjustIssuerAuthorizedShares— post-round adjustments
Functions gated by onlyAdmin (asset manager wallet only):
addAdmin,removeAdmin— admin role managementaddOperator,removeOperator— operator role management
The operator (Transfer Agent Protocol) handles all cap table operations, while the admin (asset manager) controls who has access.
Factory
The CapTableFactory (opens in a new tab) smart contract uses OpenZeppelin's upgradeable beacon pattern to create and manage upgradeable instances of cap tables for tokenized stock records. It allows developers to update the underlying cap table implementation of all instances via the beacon. New cap table instances are created with specific initial parameters (id, name, initial_shares_authorized, and operator).
The factory is permissionless — any wallet can call createCapTable and become the admin of the resulting cap table. The contract tracks each cap table proxy created, offering a function to count the total number of cap tables managed.
Cap Table
The CapTable (opens in a new tab) contract manages tokenized stock with role-based access for secure operations. It tracks stakeholders, stock classes, and transactions, supporting stock issuance, repurchase, and adjustments using the Structs Library and Stock Functions.
Delete Context
DeleteContext (opens in a new tab): Deletes stakeholders' active positions by active security IDs, stakeholder IDs, and stock class IDs.
Adjustment
Adjustment (opens in a new tab): Adjusts new shares authorized on a cap table (including tracking board approval date) after a round of funding or other event.