> For the complete documentation index, see [llms.txt](https://docs.votium.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.votium.app/explainers/opt-out-registries.md).

# Opt-Out Registries

There are two reward opt-out registries, one for Curve voting and one for f(x) voting. The registries exist for protocols that vote for their own incentivized pools and would rather their own vote not dilute the rate paid to everyone else. When a vlCVX voter opts out of a gauge, their vote for that gauge no longer earns a share of that gauge's incentives, and no longer dilutes the share paid to other voters.

Opting out is per gauge and per registry: a Curve gauge is declared on the Curve registry, an f(x) gauge on the f(x) registry. An opt-out never expires — it stands until the voter opts back in.

### For vlCVX voters who wish to opt out

vlCVX voters can find the Reward Opt-Out feature on the **My Votium** page. You may select any number of gauges from Curve or f(x) to opt out of.

The registries follow vlCVX epoch numbers, and any change takes effect in the **following** epoch. A voter who wants to opt out of, or back into, a gauge must therefore do so before the vote begins — much like delegation already works today. A change made while a vote is already open applies to the *next* vote, not the one in progress.

Opting out requires holding at least **100 vlCVX** at the epoch the change takes effect. Opting back in has no minimum and no gauge requirements, so a gauge that is later de-listed can never leave you stuck opted out of it.

Protocols that vote from a smart contract which lacks the capability of interacting with the registries may reach out to the Votium team directly to have their contract added or removed manually.

### For automated voters and reward distributors

The registries can be found at the following mainnet addresses:

* Curve: `0x5A5c248B39702E1A35bB854858B4Ae729D9c4405`
* f(x): `0x42dC5034C0699e98e2e5c0106B913c42810a618e`

Both went live in **epoch 240**. Epochs are vlCVX epoch indices, used verbatim.

#### Reading the exclusion list

`optOutCountAtEpoch(address _gauge, uint256 _epoch) external view returns (uint256)` — number of excluded addresses for one gauge. `O(log n)`, and it cannot fail on a gauge that the list functions below are too large for. Use it as a pre-flight and as a cross-check.

`optOutCountsAtEpoch(address[] calldata _gauges, uint256 _epoch) external view returns (uint256[] memory counts)` — the same, batched. Pass every gauge with deposits and get the number of excluded addresses for each one.

`optOutAtEpoch(address _gauge, uint256 _epoch) external view returns (address[] memory users)` — the full list of addresses excluded for a given gauge.

`optOutAtEpochFrom(address _gauge, uint256 _epoch, uint256 _startIndex, uint256 _maxScan) external view returns (address[] memory users, uint256 nextIndex, bool done)` — gas-safe step-over version of `optOutAtEpoch`. Call repeatedly, passing back `nextIndex`, and size the walk with `gaugeMemberCount(address _gauge)`.

{% hint style="danger" %}
**A read that fails means the gauge is too large — not that the list is empty.**

`optOutAtEpoch` has no size cap: on a large gauge it runs out of gas rather than reverting by name. Treating that as an empty set pays out to exactly the voters who asked to be excluded.

Cross-check every result against `optOutCountAtEpoch`, and switch to `optOutAtEpochFrom` when the whole-list read does not fit. Concatenating every window reproduces `optOutAtEpoch` exactly, and the totals must match the count.
{% endhint %}

{% hint style="warning" %}
**Loop `optOutAtEpochFrom` until `done` is true, not until the result is empty.**

A window containing no matches returns an empty array with `done` still `false`. Stopping there silently excludes nobody.
{% endhint %}

#### Reading withheld voting power

`withheldWeightAtEpoch(address _gauge, uint256 _epoch) external view returns (uint256)` — the vlCVX amount being excluded from a gauge, in 18 decimals, directly subtractable from the gauge total Convex reports. The registry does the whole calculation: it gathers the excluded list itself and resolves each address's votes and delegate contributions.

`withheldWeightForUsers(address _gauge, uint256 _epoch, address[] calldata _users) external view returns (uint256)` — gas-safe step-over version, taking a list of opted-out users and returning their total excluded amount. Pair it with slices from `optOutAtEpochFrom`.

Every address passed must genuinely be excluded from that gauge at that epoch, and none may repeat; both are enforced, since either would overstate what to withhold.

{% hint style="info" %}
**`withheldWeight*` accepts only epochs that carry a proposal.**

Gauge votes run on alternating epochs. An epoch without one reverts `OddEpoch` — note that the list and count functions above accept any epoch, so this restriction does not apply uniformly across the API.
{% endhint %}

#### Why not compute withheld weight yourself

The withheld figure is not simply the sum of each excluded voter's vlCVX balance. For every excluded address it counts the share of that address's own vote that went to this gauge, **plus** the share its delegate cast on its behalf. Both apply at once — an address can vote for itself and still have delegated weight counted through its delegate. Reproducing this offchain means replicating the delegation sync rules; the registry does it for you.

#### Epoch ranges

Queries outside the readable range **revert rather than returning empty**, so that a pre-deployment epoch is never mistaken for a verified "nobody opted out":

* below epoch 240 — reverts `PreDeployEpoch`
* above `currentEpoch() + 1` — reverts `FutureEpoch`

The first epoch that can report non-zero withheld weight is **242**. The registries went live during epoch 240, so the earliest an exclusion could take effect is 241, which carries no proposal. Epoch 240 returns a legitimate `0`.

Answers for settled epochs are immutable — an opt-out is never retroactive — so past results can be cached permanently.

#### Applying it

For the purpose of automated voting, a gauge's $/vlCVX should be calculated using the total vote weight reported by Convex, minus the `withheldWeight` reported by the opt-out registry.
