USD0 Revenue Distribution Module
High-Level Overview
This contract manages the automated minting and distribution of USD0 tokens to three dedicated distribution buckets. The contract enables multipurpose revenue distribution with three fixed buckets: Revenue Switch, Accruing Deposit Token (Accruing DT), and Rebasing Deposit Token (Rebasing DT). Each bucket operates independently with its own frequency, mint caps, pause mechanisms, and access control.
The core features of this contract include:
Daily Accruing Deposit Token Distribution: The contract should be called daily to calculate and mint USD0 tokens into the accruing deposit token vault (SUSD0/UsualS). The amount to mint is automatically calculated based on the vault's total assets and a configurable daily accruing yield rate. After minting, a yield distribution period is started in the vault to distribute the minted tokens over the next 24 hours.
Daily Rebasing Deposit Token Distribution: The contract should be called daily to mint a specified amount of USD0 tokens into the rebasing deposit token rewards claim contract. The amount is determined off-chain and provided as a parameter, typically based on an updated Merkle root calculated off-chain.
Weekly Revenue Switch Distribution: The contract should be called weekly to receive and mint USD0 rewards from the DAO into the revenue switch rewards claim contract. The amount is determined by the DAO and provided as a parameter when calling the function.
Mint Cap Management: The contract maintains a global operator mint cap that restricts the total amount of USD0 that can be minted through Revenue Switch and Rebasing DT distributions. Accruing DT distribution does not consume from the operator mint cap. Each bucket also has its own maximum mint cap per distribution period.
Granular Pause Mechanisms: Each distribution bucket can be paused independently, allowing for selective disabling of specific distribution channels without affecting others.
Access Control: Each functionality is controlled by a role with minimal required permissions, ensuring secure and restricted access to sensitive operations.
Contract Summary
Inherited Contracts
PausableUpgradeable: Allows contract execution to be paused or unpaused by authorized roles. Provides both global pause functionality and per-bucket pause mechanisms.
IRevenueDistributionModule: Interface that defines all functions that can be called by anyone (view functions) and role-restricted functions for revenue distribution operations.
Storage Structure
The contract uses ERC-7201 namespaced storage with the following key state variables:
operatorMintCap: Maximum amount of USD0 that can be minted globally (applies to Revenue Switch and Rebasing DT)
lastRevenueSwitchDistribution: Timestamp of last Revenue Switch distribution
lastAccruingDTDistribution: Timestamp of last Accruing DT distribution
lastRebasingDTDistribution: Timestamp of last Rebasing DT distribution
dailyAccruingYieldRate: Daily accruing yield rate in micro basis points (1 = 0.0001%)
maxRevSwitchMintCap: Maximum amount per weekly Revenue Switch distribution
maxAccruingMintCap: Maximum amount per daily Accruing DT distribution
maxRebasingDTMintCap: Maximum amount per daily Rebasing DT distribution
rewardClaimForRevenueSwitch: Address of reward claim contract for Revenue Switch
rewardClaimForAccruingDT: Address of SUSD0 vault for Accruing DT (implements ISUsd0)
rewardClaimForRebasingDT: Address of reward claim contract for Rebasing DT
revenueSwitchDistributionPaused: Boolean flag for Revenue Switch pause state
accruingDTDistributionPaused: Boolean flag for Accruing DT pause state
rebasingDTDistributionPaused: Boolean flag for Rebasing DT pause state
Functionality Description
Public/External Functions
Initialization
initialize: Initializes the contract with the registry address, reward claim contract addresses, and initial parameter values. Sets up all three distribution buckets with their initial timestamps. Can only be called once during contract deployment.
IRevenueDistributionModule - Distribution Functions
distributeRevenueSwitch:
Distributes USD0 tokens to the Revenue Switch bucket (weekly)
Requires
OPERATOR_REVSWITCH_DISTRIBUTOR_ROLEValidates that at least one week has passed since last distribution
Validates amount against maxRevSwitchMintCap and operatorMintCap
Reduces operatorMintCap by the distributed amount
Mints USD0 directly to rewardClaimForRevenueSwitch
Can only be called when Revenue Switch distribution is not paused
distributeAccruingDT:
Distributes USD0 tokens to the Accruing DT bucket (daily)
Requires
OPERATOR_ACC_DT_DISTRIBUTOR_ROLEAutomatically calculates the amount to distribute based on:
rewardClaimForAccruingDT.totalAssets() * dailyAccruingYieldRate / BASIS_MILLION_POINT_BASE
Validates that at least one day has passed since last distribution
Validates calculated amount against maxAccruingMintCap
Does not consume from operatorMintCap (unlike other distributions)
Mints USD0 directly to rewardClaimForAccruingDT vault
Starts a yield distribution period in the vault using
startYieldDistributionThe yield distribution period spans from current timestamp to current timestamp + ONE_DAY
Can only be called when Accruing DT distribution is not paused
distributeRebasingDT:
Distributes USD0 tokens to the Rebasing DT bucket (daily)
Requires
OPERATOR_REB_DT_DISTRIBUTOR_ROLETakes amount as parameter (typically calculated off-chain from Merkle root)
Validates that at least one day has passed since last distribution
Validates amount against maxRebasingDTMintCap and operatorMintCap
Reduces operatorMintCap by the distributed amount
Mints USD0 directly to rewardClaimForRebasingDT
Can only be called when Rebasing DT distribution is not paused
IRevenueDistributionModule - Configuration Functions (OPERATOR_ADMIN_ROLE)
setDailyAccruingYieldRate: Sets the daily accruing yield rate used for calculating Accruing DT distribution amounts. Rate is in micro basis points (1 = 0.0001%), must be between 0 and BASIS_MILLION_POINT_BASE.
setOperatorMintCap: Sets the global operator mint cap that limits total USD0 minting through Revenue Switch and Rebasing DT distributions.
setMaxRevSwitchMintCap: Sets the maximum amount of USD0 that can be minted per weekly Revenue Switch distribution.
setMaxAccruingMintCap: Sets the maximum amount of USD0 that can be minted per daily Accruing DT distribution.
setMaxRebasingDTMintCap: Sets the maximum amount of USD0 that can be minted per daily Rebasing DT distribution.
setRewardClaimForRevenueSwitch: Updates the reward claim contract address for Revenue Switch.
setRewardClaimForAccruingDT: Updates the reward claim contract address for Accruing DT. Must implement ISUsd0 interface.
setRewardClaimForRebasingDT: Updates the reward claim contract address for Rebasing DT.
IRevenueDistributionModule - View Functions
getOperatorMintCap: Returns the current operator mint cap value.
getDailyAccruingYieldRate: Returns the current daily accruing yield rate in micro basis points.
getRewardClaimContractForRevenueSwitch: Returns the reward claim contract address for Revenue Switch.
getRewardClaimContractForAccruingDT: Returns the reward claim contract address for Accruing DT.
getRewardClaimContractForRebasingDT: Returns the reward claim contract address for Rebasing DT.
getMaxRevSwitchMintCap: Returns the maximum amount of USD0 that can be minted per weekly Revenue Switch distribution.
getMaxAccruingMintCap: Returns the maximum amount of USD0 that can be minted per daily Accruing DT distribution.
getMaxRebasingDTMintCap: Returns the maximum amount of USD0 that can be minted per daily Rebasing DT distribution.
isRevenueSwitchDistributionPaused: Returns whether Revenue Switch distribution is currently paused.
isAccruingDTDistributionPaused: Returns whether Accruing DT distribution is currently paused.
isRebasingDTDistributionPaused: Returns whether Rebasing DT distribution is currently paused.
IRevenueDistributionModule - Pause Functions
pause: Pauses all contract operations. Can only be called by PAUSING_CONTRACTS_ROLE.
unpause: Unpauses all contract operations. Can only be called by UNPAUSING_CONTRACTS_ROLE.
pauseRevenueSwitchDistribution: Pauses only Revenue Switch distribution. Can only be called by PAUSING_CONTRACTS_ROLE.
unpauseRevenueSwitchDistribution: Unpauses Revenue Switch distribution. Can only be called by UNPAUSING_CONTRACTS_ROLE.
pauseAccruingDTDistribution: Pauses only Accruing DT distribution. Can only be called by PAUSING_CONTRACTS_ROLE.
unpauseAccruingDTDistribution: Unpauses Accruing DT distribution. Can only be called by UNPAUSING_CONTRACTS_ROLE.
pauseRebasingDTDistribution: Pauses only Rebasing DT distribution. Can only be called by PAUSING_CONTRACTS_ROLE.
unpauseRebasingDTDistribution: Unpauses Rebasing DT distribution. Can only be called by UNPAUSING_CONTRACTS_ROLE.
Functionality Breakdown
Setting up Calculation Parameters
OPERATOR_ADMIN_ROLE can change all parameter values used in distribution calculations:
Daily accruing yield rate (used in Accruing DT amount calculation)
Operator mint cap (global limit for Revenue Switch and Rebasing DT)
Individual bucket maximum mint caps
There is no timelock for these changes, allowing for rapid response to market conditions or protocol needs.
Daily Accruing Deposit Token Distribution
OPERATOR_ACC_DT_DISTRIBUTOR_ROLE is required to call distributeAccruingDT every 24 hours to:
Query the total assets value from the accruing deposit token vault (SUSD0)
Calculate the distribution amount:
totalAssets * dailyAccruingYieldRate / BASIS_MILLION_POINT_BASEValidate the calculated amount against maxAccruingMintCap
Mint the calculated amount of USD0 directly to the SUSD0 vault
Start a yield distribution period in the vault that distributes the minted tokens over the next 24 hours
Note: This distribution does not consume from the operator mint cap, as it is calculated based on vault assets rather than being an arbitrary amount set by an operator.
The amount distributed scales based on the vault's total assets, ensuring that as more users deposit into the vault, more yield is distributed proportionally.
Daily Rebasing Deposit Token Distribution
OPERATOR_REB_DT_DISTRIBUTOR_ROLE is required to call distributeRebasingDT with a valid amount every 24 hours. The amount is typically calculated off-chain based on an updated Merkle root:
Off-chain calculation determines the total USD0 amount to mint for eligible users
The amount is provided as a parameter to
distributeRebasingDTThe contract validates the amount against maxRebasingDTMintCap and operatorMintCap
If valid, the operatorMintCap is reduced by the amount
USD0 is minted directly to the rebasing deposit token rewards claim contract
Users can claim their portion using valid Merkle proofs
This distribution requires off-chain infrastructure (Watchtower) to calculate the Merkle root and determine the total distribution amount based on eligible users and their assigned allocations.
Weekly Revenue Switch Distribution
OPERATOR_REVSWITCH_DISTRIBUTOR_ROLE is required to call distributeRevenueSwitch with a valid amount every week. The amount is determined by the DAO:
DAO determines the weekly USD0 rewards amount to distribute
The amount is provided as a parameter to
distributeRevenueSwitchThe contract validates that at least one week has passed since last distribution
The contract validates the amount against maxRevSwitchMintCap and operatorMintCap
If valid, the operatorMintCap is reduced by the amount
USD0 is minted directly to the revenue switch rewards claim contract
This distribution enables the DAO to directly allocate USD0 rewards on a weekly basis, separate from the automated daily distributions.
Mint Cap Management
The contract implements a two-tier mint cap system:
Operator Mint Cap: Global limit for USD0 minting through Revenue Switch and Rebasing DT distributions. This cap is consumed when either of these distributions occurs and can be increased by
OPERATOR_ADMIN_ROLEif needed.Per-Bucket Maximum Mint Caps: Each distribution bucket has its own maximum amount that can be minted per distribution period:
maxRevSwitchMintCap: Maximum per weekly Revenue Switch distributionmaxAccruingMintCap: Maximum per daily Accruing DT distributionmaxRebasingDTMintCap: Maximum per daily Rebasing DT distribution
Both the operator mint cap and per-bucket caps must be satisfied for a distribution to proceed (except Accruing DT, which only checks its own cap).
Granular Pause Mechanisms
The contract supports both global and per-bucket pause functionality:
Global Pause: Pauses all contract operations. Can be used in emergencies to halt all distributions.
Per-Bucket Pause: Each distribution bucket can be paused independently:
pauseRevenueSwitchDistribution/unpauseRevenueSwitchDistributionpauseAccruingDTDistribution/unpauseAccruingDTDistributionpauseRebasingDTDistribution/unpauseRebasingDTDistribution
This granular control allows administrators to disable specific distribution channels without affecting others, useful for addressing issues in a single bucket or temporarily suspending specific revenue streams.
Accruing DT Yield Distribution Period
When distributeAccruingDT is called, after minting USD0 to the SUSD0 vault, the contract calls startYieldDistribution on the vault with:
yieldAmount: The minted USD0 amountstartTime: Current block timestampendTime: Current block timestamp + ONE_DAY
This initiates a yield distribution period in the vault where the minted tokens are distributed over the next 24 hours to vault holders proportionally. The vault's yield-bearing mechanism ensures that shares appreciate in value as yield accrues throughout the day.
Rebasing DT Merkle Root Integration
The Rebasing DT distribution relies on off-chain infrastructure (Watchtower) to:
Calculate eligible users and their allocations
Generate a Merkle root from these allocations
Determine the total USD0 amount to mint
Provide the amount to
distributeRebasingDT
The actual user claims happen through the rewards claim contract using Merkle proofs, not directly through the Revenue Distribution Module.
Constants
OPERATOR_REVSWITCH_DISTRIBUTOR_ROLE: Role required to distribute USD0 to Revenue Switch bucket (weekly)
OPERATOR_ACC_DT_DISTRIBUTOR_ROLE: Role required to distribute USD0 to Accruing DT bucket (daily)
OPERATOR_REB_DT_DISTRIBUTOR_ROLE: Role required to distribute USD0 to Rebasing DT bucket (daily)
OPERATOR_ADMIN_ROLE: Role required to set configuration parameters (mint caps, yield rates, reward claim addresses)
PAUSING_CONTRACTS_ROLE: Role required to pause the contract or individual distribution buckets
UNPAUSING_CONTRACTS_ROLE: Role required to unpause the contract or individual distribution buckets
CONTRACT_REGISTRY_ACCESS: Constant used to define the address of the registry access contract
CONTRACT_USD0: Constant used to define the address of the USD0 contract
INITIAL_REVENUE_DISTRIBUTION_MINT_CAP: Initial value for operator mint cap (50,000 USD0)
ONE_DAY: Duration of one day in seconds (86,400 seconds)
ONE_WEEK: Duration of one week in seconds (604,800 seconds)
BASIS_MILLION_POINT_BASE: Base value for calculating percentages in micro basis points (1,000,000, where 1 = 0.0001%)
Safeguard Implementation
Access Control
The contract uses CheckAccessControl to enforce role-based access control, ensuring only authorized addresses can perform actions that require specific permissions. Each role has minimal required permissions:
Distribution roles can only trigger their specific distribution type
Admin role can only modify configuration parameters
Pausing roles can only pause/unpause functionality
Pausability
The contract is pausable at both global and per-bucket levels:
Global pause can halt all operations in emergencies
Per-bucket pause allows selective disabling of specific distribution channels
Separate pausing and unpausing roles prevent unauthorized changes
Mint Cap Restrictions
Multiple layers of mint cap validation prevent excessive minting:
Operator mint cap limits total USD0 minting (for Revenue Switch and Rebasing DT)
Per-bucket maximum caps limit individual distribution amounts
Both caps must be satisfied for distributions to proceed
Time-Based Restrictions
Distribution functions enforce time-based restrictions to prevent abuse:
Accruing DT can only be distributed once per day
Rebasing DT can only be distributed once per day
Revenue Switch can only be distributed once per week
These restrictions prevent operators from rapidly minting excessive amounts and ensure distributions occur at appropriate intervals.
Input Validation
All functions validate inputs:
Non-zero addresses for reward claim contracts
Non-zero amounts where applicable
Yield rate bounds (0 to BASIS_MILLION_POINT_BASE)
Same value checks to prevent redundant updates
Invariant Validation
The contract maintains system invariants:
Operator mint cap cannot be exceeded (except for Accruing DT which doesn't consume it)
Distribution amounts must respect per-bucket maximum caps
Time restrictions ensure distributions occur at proper intervals
Pause states prevent distributions when buckets are disabled
Note: In scenarios where overcollateralization invariants are at risk, the contract can be paused or individual buckets can be disabled as a feature flag to protect the system.
Restrictions on Function Call Frequency
There are strict time-based limits for distribution functions:
distributeAccruingDT: Can only be called once per 24 hoursdistributeRebasingDT: Can only be called once per 24 hoursdistributeRevenueSwitch: Can only be called once per week (7 days)
These restrictions prevent unwanted emissions and ensure distributions occur at controlled, predictable intervals. The time checks use block timestamps and enforce minimum periods between distributions.
Last updated
Was this helpful?