# Supply & Investor Limits

Source: https://docs.settlemint.com/docs/architecture/security/compliance/supply-investor-limits
TokenSupplyLimit and InvestorCount modules for time-based and rolling supply caps with currency conversion, plus unique holder limits with per-country granularity.



TokenSupplyLimit checks minting against configured supply caps. InvestorCount checks whether adding a recipient would exceed configured holder-count limits.

## Where these modules apply [#where-these-modules-apply]

| Concern          | TokenSupplyLimit                          | InvestorCount                         |
| ---------------- | ----------------------------------------- | ------------------------------------- |
| Minting          | Enforces cap (lifetime / fixed / rolling) | Tracks new holders                    |
| Transfers        | Not checked                               | Tracks new holders                    |
| Burns            | Not checked                               | Decrements count                      |
| Forced transfers | Not checked                               | Tracks new holders after the transfer |

## TokenSupplyLimit [#tokensupplylimit]

Enforces maximum token supply limits, with optional base-price conversion for EUR/USD-denominated caps.

### Interface (capabilities) [#interface-capabilities]

| Capability                | Who can call                 | Inputs                                             | On-chain effect                                                                     | Emits | Notes                                                                  |
| ------------------------- | ---------------------------- | -------------------------------------------------- | ----------------------------------------------------------------------------------- | ----- | ---------------------------------------------------------------------- |
| `setModuleParameters`     | Token admin (via compliance) | `maxSupply`, `limitType`, `period`, `useBasePrice` | Stores supply-limit config; `validateParameters` reverts if `maxSupply = 0`         | None  | Calling with `maxSupply = 0` reverts; the cap must be a positive value |
| `canTransfer` (mint path) | Compliance engine            | Sender, recipient, amount                          | Checks cumulative supply against limit (converts via price claim if `useBasePrice`) | None  | Only enforced on mints (`from == address(0)`)                          |

### Supply limit types [#supply-limit-types]

| Type            | Behavior                               | Use case                                        |
| --------------- | -------------------------------------- | ----------------------------------------------- |
| LIFETIME        | Total cap across the token's lifetime  | MiCA EUR 8M asset-referenced token limit        |
| FIXED\_PERIOD   | Cap resets at the start of each period | Quarterly fundraising caps                      |
| ROLLING\_PERIOD | Sliding window of last N days          | Continuous monitoring (rolling 12-month limits) |

### Base currency conversion [#base-currency-conversion]

When an admin enables `useBasePrice`, the module converts token amounts using on-chain price claims before checking the supply limit. The conversion supports EUR- or USD-denominated caps on tokens priced in native units.

### Key invariants [#key-invariants]

* Supply limit applies to minting operations only; transfers and burns are not checked.
* ROLLING\_PERIOD uses a sliding window; older mints fall off as time passes.
* FIXED\_PERIOD resets at the start of each new period, regardless of previous minting.
* Calling `setModuleParameters` with `maxSupply = 0` reverts; the cap must be a positive value.

### Operational signals [#operational-signals]

No events emitted by this module. Monitor for `ComplianceCheckFailed` revert errors in failed transactions when minting exceeds the configured limit.

### Failure modes & edge cases [#failure-modes--edge-cases]

* Missing or stale price feed when `useBasePrice` is active: minting reverts until a valid price claim exists.
* ROLLING\_PERIOD window boundary: mints near the window edge may succeed or fail depending on when older mints age out.

***

## InvestorCount [#investorcount]

Restricts the number of unique token holders. The `topicFilter` determines which investors count toward the limit, not which investors identity verification blocks.

### Interface (capabilities) [#interface-capabilities-1]

| Capability            | Who can call                 | Inputs                                                                            | On-chain effect                                                 | Emits | Notes                                                                      |
| --------------------- | ---------------------------- | --------------------------------------------------------------------------------- | --------------------------------------------------------------- | ----- | -------------------------------------------------------------------------- |
| `setModuleParameters` | Token admin (via compliance) | `maxInvestors`, `countryCodes[]`, `countryLimits[]`, `topicFilter`, `global` flag | Stores investor-count config                                    | None  | `topicFilter` uses the same RPN expression system as identity verification |
| `canTransfer`         | Compliance engine            | Sender, recipient, amount                                                         | Checks if adding recipient would exceed global or country limit | None  | Skips burns (`to == address(0)`); applies to mints and transfers           |

### How it works [#how-it-works]

| Investor state                        | Identity module result     | InvestorCount result            | Transfer outcome |
| ------------------------------------- | -------------------------- | ------------------------------- | ---------------- |
| No KYC/AML claims                     | Blocked by identity module | N/A (never reaches count check) | Transfer blocked |
| Has qualifying claims, count \< limit | Allowed                    | Counted                         | Transfer allowed |
| Has qualifying claims, count = limit  | Allowed                    | Blocked (over limit)            | Transfer blocked |

### topicFilter and limits [#topicfilter-and-limits]

The `topicFilter` is a claim expression (same [RPN system](/docs/architecture/security/compliance/identity-verification) as SMARTIdentityVerification) that determines which investors count toward the limit. InvestorCount can enforce a global limit across all investors and per-country limits for jurisdiction-specific restrictions (e.g., max 50 Singapore residents).

### Key invariants [#key-invariants-1]

* `canTransfer` skips burns (`to == address(0)`) but applies to both mints and transfers.
* The active tracker depends on the `global` flag. With `global` enabled, tokens using the same InvestorCount module instance share one investor tracker. Use separate module instances when policies need isolated counts. Otherwise, counts are token-specific.
* InvestorCount checks per-country limits independently of the global limit; both must pass when configured.
* `topicFilter` determines who counts toward InvestorCount. Identity verification handles blocking.
* InvestorCount does not count addresses without a registered identity; use identity verification when the policy must block unverified recipients.

### Operational signals [#operational-signals-1]

No events emitted by this module. Monitor for `ComplianceCheckFailed` revert errors in failed transactions when investor count exceeds limits.

### Failure modes & edge cases [#failure-modes--edge-cases-1]

* Forced transfers bypass the pre-transfer investor-limit check but still update holder tracking after the transfer. A forced transfer to a new holder can leave the current investor count above the configured limit. Later movements can bring the count back within policy.
* Missing country code in the identity registry: InvestorCount counts the investor globally when a global limit is configured, but not toward a per-country limit.

## See also [#see-also]

* [Compliance Overview](/docs/architecture/security/compliance) - module architecture and regulatory templates
* [Identity Verification](/docs/architecture/security/compliance/identity-verification) - `topicFilter` uses the same RPN expression system
* [Transfer Approval](/docs/architecture/security/compliance/transfer-approval) - pre-approval controls complement investor count limits
* [Supply Cap & Collateral](/docs/architecture/security/compliance/supply-cap-collateral) - CappedComplianceModule for hard circulating supply caps
