Quantillon Protocol

Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

UserPool

Git Source

Inherits: Initializable, ReentrancyGuardUpgradeable, AccessControlUpgradeable, PausableUpgradeable, SecureUpgradeable

Author: Quantillon Labs - Nicolas Bellengé - @chewbaccoin

Manages QEURO user deposits, staking, and yield distribution

Main characteristics:

  • User deposit and withdrawal management
  • QEURO staking mechanism with rewards
  • Yield distribution system
  • Fee structure for protocol sustainability
  • Emergency pause mechanism for crisis situations
  • Upgradeable via UUPS pattern

Deposit mechanics:

  • Users deposit USDC to receive QEURO
  • QEURO is minted based on current EUR/USD exchange rate
  • Deposit fees charged for protocol revenue
  • Deposits are tracked per user for analytics

Staking mechanics:

  • Users can stake their QEURO for additional rewards
  • Staking APY provides yield on staked QEURO
  • Unstaking has a cooldown period to prevent abuse
  • Rewards are distributed based on staking duration and amount

Withdrawal mechanics:

  • Users can withdraw their QEURO back to USDC
  • Withdrawal fees charged for protocol revenue
  • Withdrawals are processed based on current EUR/USD rate
  • Staked QEURO must be unstaked before withdrawal

Yield distribution:

  • Yield is distributed to stakers based on their stake amount
  • Performance fees charged on yield distributions
  • Yield sources include protocol fees and yield shift mechanisms
  • Real-time yield tracking and distribution

Fee structure:

  • Deposit fees for creating QEURO from USDC
  • Withdrawal fees for converting QEURO back to USDC
  • Performance fees on yield distributions
  • Dynamic fee adjustment based on market conditions

Security features:

  • Role-based access control for all critical operations
  • Reentrancy protection for all external calls
  • Emergency pause mechanism for crisis situations
  • Upgradeable architecture for future improvements
  • Secure deposit and withdrawal management
  • Staking cooldown mechanisms
  • Batch size limits to prevent DoS attacks
  • Gas optimization through storage read caching

Integration points:

  • QEURO token for minting and burning
  • USDC for deposits and withdrawals
  • QuantillonVault for QEURO minting/burning
  • Yield shift mechanism for yield management
  • Vault math library for calculations

Note: security-contact: team@quantillon.money

State Variables

GOVERNANCE_ROLE

Role for governance operations (parameter updates, emergency actions)

keccak256 hash avoids role collisions with other contracts

Should be assigned to governance multisig or DAO

bytes32 public constant GOVERNANCE_ROLE = keccak256("GOVERNANCE_ROLE")

EMERGENCY_ROLE

Role for emergency operations (pause, emergency withdrawals)

keccak256 hash avoids role collisions with other contracts

Should be assigned to emergency multisig

bytes32 public constant EMERGENCY_ROLE = keccak256("EMERGENCY_ROLE")

qeuro

QEURO token contract for minting and burning

Used for all QEURO minting and burning operations

Should be the official QEURO token contract

IQEUROToken public qeuro

usdc

USDC token contract for deposits and withdrawals

Used for all USDC deposits and withdrawals

Should be the official USDC contract on the target network

IERC20 public usdc

vault

Main Quantillon vault for QEURO operations

Used for QEURO minting and burning operations

Should be the official QuantillonVault contract

IQuantillonVault public vault

oracle

Chainlink Oracle for EUR/USD price feeds

Used for converting QEURO supply to USDC equivalent in analytics

IChainlinkOracle public oracle

yieldShift

Yield shift mechanism for yield management

Handles yield distribution and management

Used for yield calculations and distributions

IYieldShift public yieldShift

treasury

Treasury address for ETH recovery

SECURITY: Only this address can receive ETH from recoverETH function

address public treasury

TIME_PROVIDER

TimeProvider contract for centralized time management

Used to replace direct block.timestamp usage for testability and consistency

TimeProvider public immutable TIME_PROVIDER

stakingAPY

Staking APY in basis points

Example: 500 = 5% staking APY

Used for calculating staking rewards

uint256 public stakingAPY

depositAPY

Base deposit APY in basis points

Example: 200 = 2% base deposit APY

Used for calculating deposit rewards

uint256 public depositAPY

minStakeAmount

Minimum amount required for staking (in QEURO)

Example: 100 * 1e18 = 100 QEURO minimum stake

Prevents dust staking and reduces gas costs

uint256 public minStakeAmount

unstakingCooldown

Cooldown period for unstaking (in seconds)

Example: 7 days = 604,800 seconds

Prevents rapid staking/unstaking cycles

uint256 public unstakingCooldown

depositFee

Fee charged on deposits (in basis points)

Example: 10 = 0.1% deposit fee

Revenue source for the protocol

uint256 public depositFee

withdrawalFee

Fee charged on withdrawals (in basis points)

Example: 10 = 0.1% withdrawal fee

Revenue source for the protocol

uint256 public withdrawalFee

performanceFee

Fee charged on yield distributions (in basis points)

Example: 200 = 2% performance fee

Revenue source for the protocol

uint256 public performanceFee

totalStakes

Total QEURO staked across all users

Sum of all staked QEURO amounts

Used for yield distribution calculations

uint256 public totalStakes

totalUsers

Number of unique users who have deposited

Count of unique addresses that have made deposits

Used for protocol analytics and governance

uint256 public totalUsers

userInfo

User information by address

Maps user addresses to their detailed information

Used to track user deposits, stakes, and rewards

mapping(address => UserInfo) public userInfo

hasDeposited

Whether a user has ever deposited

Maps user addresses to their deposit status

Used to track unique users and prevent double counting

mapping(address => bool) public hasDeposited

accumulatedYieldPerShare

Accumulated yield per staked QEURO share

Used for calculating user rewards based on their stake amount

Increases over time as yield is distributed

uint256 public accumulatedYieldPerShare

lastYieldDistribution

Timestamp of last yield distribution

Used to track when yield was last distributed

Used for yield calculation intervals

uint256 public lastYieldDistribution

totalYieldDistributed

Total yield distributed to users

Sum of all yield distributed to users

Used for protocol analytics and governance

uint256 public totalYieldDistributed

totalUserDeposits

Total USDC deposits across all users (in USDC decimals - 6)

Tracks the sum of all USDC deposits made by users

Used for protocol analytics and collateralization calculations

uint256 public totalUserDeposits

totalUserWithdrawals

Total QEURO withdrawals across all users (in QEURO decimals - 18)

Tracks the sum of all QEURO withdrawals made by users

Used for protocol analytics and supply tracking

uint256 public totalUserWithdrawals

userDeposits

User deposit tracking with oracle ratios

Maps user addresses to their deposit history with oracle ratios

Used for detailed analytics and audit trails

mapping(address => UserDepositInfo[]) public userDeposits

userWithdrawals

User withdrawal tracking with oracle ratios

Maps user addresses to their withdrawal history with oracle ratios

Used for detailed analytics and audit trails

mapping(address => UserWithdrawalInfo[]) public userWithdrawals

userLastRewardBlock

mapping(address => uint256) public userLastRewardBlock

BLOCKS_PER_DAY

uint256 public constant BLOCKS_PER_DAY = 7200

MAX_REWARD_PERIOD

uint256 public constant MAX_REWARD_PERIOD = 365 days

MAX_BATCH_SIZE

Maximum batch size for deposit operations to prevent DoS

Prevents out-of-gas attacks through large arrays

uint256 public constant MAX_BATCH_SIZE = 100

MAX_REWARD_BATCH_SIZE

Maximum batch size for reward claim operations to prevent DoS

Prevents out-of-gas attacks through large user arrays

uint256 public constant MAX_REWARD_BATCH_SIZE = 50

Functions

flashLoanProtection

Modifier to protect against flash loan attacks

Uses the FlashLoanProtectionLibrary to check USDC balance consistency

modifier flashLoanProtection() ;

constructor

Constructor for UserPool contract

Sets up the time provider and disables initializers for security

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Disables initializers

  • events: No events emitted

  • errors: Throws custom errors for invalid conditions

  • reentrancy: No reentrancy protection needed

  • access: No access restrictions

  • oracle: No oracle dependencies

constructor(TimeProvider _TIME_PROVIDER) ;

Parameters

NameTypeDescription
_TIME_PROVIDERTimeProviderTimeProvider contract for centralized time management

initialize

Initializes the UserPool contract

Initializes the UserPool with all required contracts and default parameters

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Initializes all contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by reentrancy guard

  • access: Restricted to initializer modifier

  • oracle: Requires oracle for analytics functions

function initialize(
    address admin,
    address _qeuro,
    address _usdc,
    address _vault,
    address _oracle,
    address _yieldShift,
    address _timelock,
    address _treasury
) public initializer;

Parameters

NameTypeDescription
adminaddressAddress that receives admin and governance roles
_qeuroaddressAddress of the QEURO token contract
_usdcaddressAddress of the USDC token contract
_vaultaddressAddress of the QuantillonVault contract
_oracleaddressAddress of the Chainlink Oracle contract
_yieldShiftaddressAddress of the YieldShift contract
_timelockaddressAddress of the timelock contract
_treasuryaddressAddress of the treasury contract

deposit

Deposit USDC to mint QEURO (unified single/batch function)

Handles both single deposits and batch deposits in one function

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Updates contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by nonReentrant modifier

  • access: Public access

  • oracle: No oracle dependencies

function deposit(uint256[] calldata usdcAmounts, uint256[] calldata minQeuroOuts)
    external
    nonReentrant
    whenNotPaused
    flashLoanProtection
    returns (uint256[] memory qeuroMintedAmounts);

Parameters

NameTypeDescription
usdcAmountsuint256[]Array of USDC amounts to deposit (6 decimals) - use [amount] for single
minQeuroOutsuint256[]Array of minimum QEURO amounts to receive (18 decimals) - use [amount] for single

Returns

NameTypeDescription
qeuroMintedAmountsuint256[]Array of QEURO amounts minted (18 decimals)

_validateAndTransferTokens

Internal function to validate amounts and transfer tokens (unified validation)

Unified validation and transfer function to reduce code duplication

Notes:

  • security: Validates all amounts > 0 before transfer

  • validation: Validates each amount in array is positive

  • state-changes: Transfers tokens from/to msg.sender

  • events: No events emitted - handled by calling function

  • errors: Throws if any amount is 0

  • reentrancy: Not protected - internal function only

  • access: Internal function - no access restrictions

  • oracle: No oracle dependencies

function _validateAndTransferTokens(uint256[] calldata amounts, IERC20 token, bool isFromUser)
    internal
    returns (uint256 totalAmount);

Parameters

NameTypeDescription
amountsuint256[]Array of amounts to validate and transfer
tokenIERC20Token to transfer (usdc or qeuro)
isFromUserboolWhether to transfer from user (true) or to user (false)

Returns

NameTypeDescription
totalAmountuint256Total amount transferred

_initializeUserIfNeeded

Internal function to initialize user if needed (consolidated)

Initializes user tracking if they haven't deposited before

Notes:

  • security: Updates hasDeposited mapping and totalUsers counter

  • validation: No input validation required

  • state-changes: Updates hasDeposited[msg.sender] and totalUsers

  • events: No events emitted

  • errors: No errors thrown

  • reentrancy: Not protected - internal function only

  • access: Internal function - no access restrictions

  • oracle: No oracle dependencies

function _initializeUserIfNeeded() internal;

_calculateNetAmounts

Internal function to calculate net amounts after fees

Calculates net amounts by subtracting deposit fees from each USDC amount

Notes:

  • security: Uses cached depositFee to prevent reentrancy

  • validation: No input validation required - view function

  • state-changes: No state changes - view function only

  • events: No events emitted

  • errors: No errors thrown

  • reentrancy: Not applicable - view function

  • access: Internal function - no access restrictions

  • oracle: No oracle dependencies

function _calculateNetAmounts(uint256[] calldata usdcAmounts)
    internal
    view
    returns (uint256[] memory netAmounts, uint256 totalNetAmount);

Parameters

NameTypeDescription
usdcAmountsuint256[]Array of USDC amounts (6 decimals)

Returns

NameTypeDescription
netAmountsuint256[]Array of net amounts after fees (6 decimals)
totalNetAmountuint256Total net amount (6 decimals)

_processVaultMinting

Internal function to process vault minting operations

Processes vault minting operations with single vault call to avoid external calls in loop

Notes:

  • security: Uses single approval and single vault call to minimize external calls

  • validation: No input validation required - parameters pre-validated

  • state-changes: Updates qeuroMintedAmounts array with minted amounts

  • events: No events emitted - handled by calling function

  • errors: Throws if vault.mintQEURO fails

  • reentrancy: Protected by nonReentrant modifier on calling function

  • access: Internal function - no access restrictions

  • oracle: No oracle dependencies

function _processVaultMinting(
    uint256[] memory netAmounts,
    uint256[] calldata minQeuroOuts,
    uint256[] memory qeuroMintedAmounts
) internal;

Parameters

NameTypeDescription
netAmountsuint256[]Array of net amounts to mint (6 decimals)
minQeuroOutsuint256[]Array of minimum QEURO outputs (18 decimals)
qeuroMintedAmountsuint256[]Array to store minted amounts (18 decimals)

_updateUserAndPoolState

Internal function to update user and pool state

Updates user and pool state before external calls for reentrancy protection

Notes:

  • security: Updates state before external calls (CEI pattern)

  • validation: No input validation required - parameters pre-validated

  • state-changes: Updates user.depositHistory, totalDeposits

  • events: No events emitted - handled by calling function

  • errors: No errors thrown

  • reentrancy: Not protected - internal function only

  • access: Internal function - no access restrictions

  • oracle: No oracle dependencies

function _updateUserAndPoolState(
    uint256[] calldata usdcAmounts,
    uint256[] calldata minQeuroOuts,
    uint256 /* totalNetAmount */
)
    internal;

Parameters

NameTypeDescription
usdcAmountsuint256[]Array of USDC amounts (6 decimals)
minQeuroOutsuint256[]Array of minimum QEURO outputs (18 decimals)
<none>uint256

_transferQeuroAndEmitEvents

Internal function to transfer QEURO and emit events

Transfers QEURO to users and emits UserDeposit events

Notes:

  • security: Uses SafeERC20 for secure token transfers

  • validation: No input validation required - parameters pre-validated

  • state-changes: Transfers QEURO tokens to msg.sender

  • events: Emits UserDeposit event for each transfer

  • errors: Throws if QEURO transfer fails

  • reentrancy: Not protected - internal function only

  • access: Internal function - no access restrictions

  • oracle: No oracle dependencies

function _transferQeuroAndEmitEvents(
    uint256[] calldata usdcAmounts,
    uint256[] memory qeuroMintedAmounts,
    uint256 currentTime
) internal;

Parameters

NameTypeDescription
usdcAmountsuint256[]Array of USDC amounts (6 decimals)
qeuroMintedAmountsuint256[]Array of minted QEURO amounts (18 decimals)
currentTimeuint256Current timestamp

withdraw

Withdraw USDC by burning QEURO (unified single/batch function)

Handles both single withdrawals and batch withdrawals in one function

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Updates contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by nonReentrant modifier

  • access: Public access

  • oracle: No oracle dependencies

function withdraw(uint256[] calldata qeuroAmounts, uint256[] calldata minUsdcOuts)
    external
    nonReentrant
    whenNotPaused
    returns (uint256[] memory usdcReceivedAmounts);

Parameters

NameTypeDescription
qeuroAmountsuint256[]Array of QEURO amounts to burn (18 decimals) - use [amount] for single
minUsdcOutsuint256[]Array of minimum USDC amounts to receive (6 decimals) - use [amount] for single

Returns

NameTypeDescription
usdcReceivedAmountsuint256[]Array of USDC amounts received (6 decimals)

_validateAndProcessBatchWithdrawal

Validates and processes batch withdrawal

Internal helper to reduce stack depth

Notes:

  • security: Validates amounts and user balances to prevent over-withdrawal

  • validation: Validates all amounts are positive and user has sufficient balance

  • state-changes: Updates user balance and processes withdrawal calculations

  • events: No events emitted - internal helper function

  • errors: Throws "Amount must be positive" if any amount is zero

  • reentrancy: Not protected - internal function only

  • access: Internal function - no access restrictions

  • oracle: No oracle dependencies

function _validateAndProcessBatchWithdrawal(
    uint256[] calldata qeuroAmounts,
    uint256[] calldata minUsdcOuts,
    uint256[] memory usdcReceivedAmounts
) internal;

Parameters

NameTypeDescription
qeuroAmountsuint256[]Array of QEURO amounts to withdraw
minUsdcOutsuint256[]Array of minimum USDC amounts expected
usdcReceivedAmountsuint256[]Array to store received USDC amounts

_processVaultRedemptions

Processes vault redemptions for batch withdrawal

Internal helper to reduce stack depth

OPTIMIZATION: Uses single vault call with total amounts to avoid external calls in loop

Notes:

  • security: Validates vault redemption amounts and minimum outputs

  • validation: Validates all amounts are positive and within limits

  • state-changes: Processes vault redemptions and updates received amounts

  • events: No events emitted - internal helper function

  • errors: Throws validation errors if amounts are invalid

  • reentrancy: Not protected - internal function only

  • access: Internal function - no access restrictions

  • oracle: No oracle dependencies

function _processVaultRedemptions(
    uint256[] calldata qeuroAmounts,
    uint256[] calldata minUsdcOuts,
    uint256[] memory usdcReceivedAmounts,
    uint256 withdrawalFee_
) internal;

Parameters

NameTypeDescription
qeuroAmountsuint256[]Array of QEURO amounts to redeem
minUsdcOutsuint256[]Array of minimum USDC amounts expected
usdcReceivedAmountsuint256[]Array to store received USDC amounts
withdrawalFee_uint256Cached withdrawal fee percentage

_executeBatchTransfers

Executes final transfers and emits events for batch withdrawal

Internal helper to reduce stack depth

Notes:

  • security: Executes final token transfers and emits withdrawal events

  • validation: Validates all amounts are positive before transfer

  • state-changes: Burns QEURO tokens and transfers USDC to user

  • events: Emits Withdrawal event for each withdrawal

  • errors: Throws transfer errors if token operations fail

  • reentrancy: Not protected - internal function only

  • access: Internal function - no access restrictions

  • oracle: No oracle dependencies

function _executeBatchTransfers(
    uint256[] calldata qeuroAmounts,
    uint256[] memory usdcReceivedAmounts,
    uint256 currentTime
) internal;

Parameters

NameTypeDescription
qeuroAmountsuint256[]Array of QEURO amounts withdrawn
usdcReceivedAmountsuint256[]Array of USDC amounts received
currentTimeuint256Current timestamp for events

stake

Stakes QEURO tokens (unified single/batch function)

Handles both single stakes and batch stakes in one function

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Updates contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by nonReentrant modifier

  • access: Public access

  • oracle: No oracle dependencies

function stake(uint256[] calldata qeuroAmounts) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
qeuroAmountsuint256[]Array of QEURO amounts to stake (18 decimals) - use [amount] for single

requestUnstake

Requests to unstake QEURO tokens (starts unstaking cooldown period)

Begins the unstaking process with a cooldown period before tokens can be withdrawn

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Updates contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by nonReentrant modifier

  • access: Public access

  • oracle: No oracle dependencies

function requestUnstake(uint256 qeuroAmount) external nonReentrant;

Parameters

NameTypeDescription
qeuroAmountuint256The amount of staked QEURO tokens to unstake (18 decimals)

unstake

Complete unstaking after cooldown period

This function allows users to complete their unstaking request after the cooldown period has passed.

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Updates contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by nonReentrant modifier

  • access: Public access

  • oracle: No oracle dependencies

function unstake() external nonReentrant whenNotPaused;

claimStakingRewards

Claim staking rewards

This function allows users to claim their pending staking rewards. It calculates and transfers the rewards based on their staked amount.

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Updates contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by reentrancy guard

  • access: Restricted to authorized roles

  • oracle: Requires fresh oracle price data

function claimStakingRewards() external nonReentrant returns (uint256 rewardAmount);

Returns

NameTypeDescription
rewardAmountuint256Amount of QEURO rewards claimed (18 decimals)

batchRewardClaim

Batch claim staking rewards for multiple users (admin function)

This function allows admins to claim rewards for multiple users in one transaction. Useful for protocol-wide reward distributions or automated reward processing.

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Updates contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by reentrancy guard

  • access: Restricted to authorized roles

  • oracle: Requires fresh oracle price data

function batchRewardClaim(address[] calldata users)
    external
    nonReentrant
    onlyRole(GOVERNANCE_ROLE)
    returns (uint256[] memory rewardAmounts);

Parameters

NameTypeDescription
usersaddress[]Array of user addresses to claim rewards for

Returns

NameTypeDescription
rewardAmountsuint256[]Array of reward amounts claimed for each user (18 decimals)

distributeYield

Distribute yield to stakers (called by YieldShift contract)

This function is deprecated - yield now goes to stQEURO

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Updates contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by reentrancy guard

  • access: Restricted to authorized roles

  • oracle: Requires fresh oracle price data

function distributeYield(uint256 yieldAmount) external;

Parameters

NameTypeDescription
yieldAmountuint256Amount of yield to distribute (18 decimals)

_updatePendingRewards

Update pending rewards for a user

This internal function calculates and updates the pending rewards for a given user based on their staked amount and the current APY. Uses block-based calculations to prevent timestamp manipulation.

Notes:

  • security: Uses block-based calculations to prevent timestamp manipulation

  • validation: Validates user has staked amount > 0

  • state-changes: Updates user.pendingRewards, user.lastStakeTime, userLastRewardBlock

  • events: No events emitted - handled by calling function

  • errors: No errors thrown - safe arithmetic used

  • reentrancy: Not protected - internal function only

  • access: Internal function - no access restrictions

  • oracle: No oracle dependencies

function _updatePendingRewards(address user, uint256 currentTime) internal;

Parameters

NameTypeDescription
useraddressAddress of the user to update
currentTimeuint256Current timestamp for reward calculations

getUserInfo

Get comprehensive user information (consolidated view function)

Returns all user-related data in one call to reduce contract size

Notes:

  • security: No security implications (view function)

  • validation: No validation required

  • state-changes: No state changes (view function)

  • events: No events (view function)

  • errors: No custom errors

  • reentrancy: No external calls, safe

  • access: Public (anyone can call)

  • oracle: No oracle dependencies

function getUserInfo(address user)
    external
    view
    returns (
        uint256 qeuroBalance,
        uint256 stakedAmount,
        uint256 pendingRewards,
        uint256 depositHistory,
        uint256 lastStakeTime,
        uint256 unstakeAmount,
        uint256 unstakeRequestTime
    );

Parameters

NameTypeDescription
useraddressAddress of the user to query

Returns

NameTypeDescription
qeuroBalanceuint256QEURO balance of the user (18 decimals)
stakedAmountuint256Current staked amount of the user (18 decimals)
pendingRewardsuint256Total pending rewards of the user (18 decimals)
depositHistoryuint256Total historical deposits of the user (6 decimals)
lastStakeTimeuint256Timestamp of the user's last staking action
unstakeAmountuint256Amount being unstaked (18 decimals)
unstakeRequestTimeuint256Timestamp when unstaking was requested

getPoolTotals

Get comprehensive pool totals (consolidated view function)

Returns all pool totals in one call to reduce contract size

Notes:

  • security: No security implications (view function)

  • validation: No validation required

  • state-changes: No state changes (view function)

  • events: No events (view function)

  • errors: No custom errors

  • reentrancy: No external calls, safe

  • access: Public (anyone can call)

  • oracle: No oracle dependencies

function getPoolTotals()
    external
    view
    returns (uint256 totalDeposits, uint256 totalWithdrawals, uint256 totalStakes_, uint256 totalUsers_);

Returns

NameTypeDescription
totalDepositsuint256Total USDC deposits (6 decimals)
totalWithdrawalsuint256Total QEURO withdrawals (18 decimals)
totalStakes_uint256Total QEURO staked (18 decimals)
totalUsers_uint256Total number of users

getUserDepositHistory

Get user deposit history with oracle ratios

Used for detailed analytics and audit trails

Returns complete deposit history with oracle ratios

Notes:

  • security: No security implications (view function)

  • validation: No validation required

  • state-changes: No state changes (view function)

  • events: No events (view function)

  • errors: No custom errors

  • reentrancy: No external calls, safe

  • access: Public (anyone can call)

  • oracle: No oracle dependencies

function getUserDepositHistory(address user) external view returns (UserDepositInfo[] memory);

Parameters

NameTypeDescription
useraddressAddress of the user

Returns

NameTypeDescription
<none>UserDepositInfo[]Array of UserDepositInfo structs containing deposit history

getUserWithdrawals

Get user withdrawal history with oracle ratios

Used for detailed analytics and audit trails

Returns complete withdrawal history with oracle ratios

Notes:

  • security: No security implications (view function)

  • validation: No validation required

  • state-changes: No state changes (view function)

  • events: No events (view function)

  • errors: No custom errors

  • reentrancy: No external calls, safe

  • access: Public (anyone can call)

  • oracle: No oracle dependencies

function getUserWithdrawals(address user) external view returns (UserWithdrawalInfo[] memory);

Parameters

NameTypeDescription
useraddressAddress of the user

Returns

NameTypeDescription
<none>UserWithdrawalInfo[]Array of UserWithdrawalInfo structs containing withdrawal history

_getOracleRatioScaled

Get current oracle ratio scaled by 1e6 for storage efficiency

Used internally for tracking oracle ratios in deposit/withdrawal records

Scaled to fit in uint32 for gas efficiency

Notes:

  • security: No security implications (view function)

  • validation: No validation required

  • state-changes: No state changes (view function)

  • events: No events (view function)

  • errors: No custom errors

  • reentrancy: No external calls, safe

  • access: Internal function

  • oracle: Depends on oracle for current EUR/USD rate

function _getOracleRatioScaled() internal returns (uint32);

Returns

NameTypeDescription
<none>uint32Oracle ratio scaled by 1e6 (e.g., 1.08 becomes 1080000)

getTotalStakes

Get the total USDC equivalent withdrawals across all users

Get the total QEURO staked across all users

Used for analytics and cash flow monitoring

Returns the total amount of QEURO currently staked in the pool

Notes:

  • access: Public access

  • oracle: No oracle dependencies

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Updates contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by reentrancy guard

  • access: Restricted to authorized roles

  • oracle: Requires fresh oracle price data

function getTotalStakes() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256Total withdrawals in USDC equivalent (6 decimals)

getPoolMetrics

Get various metrics about the user pool

Returns comprehensive pool statistics including user count, averages, and ratios

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Updates contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by reentrancy guard

  • access: Restricted to authorized roles

  • oracle: Requires fresh oracle price data

function getPoolMetrics()
    external
    view
    returns (uint256 totalUsers_, uint256 averageDeposit, uint256 stakingRatio, uint256 poolTVL);

Returns

NameTypeDescription
totalUsers_uint256Number of unique users
averageDeposituint256Average deposit amount per user (6 decimals)
stakingRatiouint256Ratio of total staked QEURO to total deposits (basis points)
poolTVLuint256Total value locked in the pool (6 decimals)

getPoolAnalytics

Get comprehensive pool analytics using QEURO total supply

Uses QEURO total supply for accurate analytics instead of misleading USDC tracking

Notes:

  • security: No external calls except oracle, read-only function

  • validation: Oracle price validation with fallback to zero

  • state-changes: No state changes, view-like function

  • events: No events emitted

  • errors: No custom errors, handles oracle failures gracefully

  • reentrancy: No reentrancy risk, read-only operations

  • access: Public access

  • oracle: Requires fresh oracle price data for USDC equivalent

function getPoolAnalytics()
    external
    returns (
        uint256 currentQeuroSupply,
        uint256 usdcEquivalentAtCurrentRate,
        uint256 totalUsers_,
        uint256 totalStakes_
    );

Returns

NameTypeDescription
currentQeuroSupplyuint256Current QEURO total supply (net minted QEURO)
usdcEquivalentAtCurrentRateuint256Current USDC equivalent of QEURO supply
totalUsers_uint256Total number of users
totalStakes_uint256Total QEURO staked

getPoolConfiguration

Get comprehensive pool configuration (consolidated view function)

Returns all pool configuration parameters in one call to reduce contract size

Notes:

  • security: No security implications (view function)

  • validation: No validation required

  • state-changes: No state changes (view function)

  • events: No events (view function)

  • errors: No custom errors

  • reentrancy: No external calls, safe

  • access: Public (anyone can call)

  • oracle: No oracle dependencies

function getPoolConfiguration()
    external
    view
    returns (
        uint256 stakingAPY_,
        uint256 depositAPY_,
        uint256 minStakeAmount_,
        uint256 unstakingCooldown_,
        uint256 depositFee_,
        uint256 withdrawalFee_,
        uint256 performanceFee_
    );

Returns

NameTypeDescription
stakingAPY_uint256Current staking APY in basis points
depositAPY_uint256Current deposit APY in basis points
minStakeAmount_uint256Current minimum stake amount (18 decimals)
unstakingCooldown_uint256Current unstaking cooldown period (seconds)
depositFee_uint256Current deposit fee (basis points)
withdrawalFee_uint256Current withdrawal fee (basis points)
performanceFee_uint256Current performance fee (basis points)

calculateProjectedRewards

Calculate projected rewards for a given QEURO amount and duration

Calculates the expected rewards for staking a specific amount for a given duration

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Updates contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by reentrancy guard

  • access: Restricted to authorized roles

  • oracle: Requires fresh oracle price data

function calculateProjectedRewards(uint256 qeuroAmount, uint256 duration) external view returns (uint256);

Parameters

NameTypeDescription
qeuroAmountuint256Amount of QEURO to calculate rewards for (18 decimals)
durationuint256Duration in seconds

Returns

NameTypeDescription
<none>uint256uint256 Calculated rewards (18 decimals)

updateStakingParameters

Update the parameters for staking (APY, min stake, cooldown)

This function is restricted to governance roles.

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Updates contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by reentrancy guard

  • access: Restricted to authorized roles

  • oracle: Requires fresh oracle price data

function updateStakingParameters(uint256 newStakingAPY, uint256 newMinStakeAmount, uint256 newUnstakingCooldown)
    external
    onlyRole(GOVERNANCE_ROLE);

Parameters

NameTypeDescription
newStakingAPYuint256New Staking APY in basis points
newMinStakeAmountuint256New Minimum stake amount (18 decimals)
newUnstakingCooldownuint256New unstaking cooldown period (seconds)

setPoolFees

Set the fees for deposits, withdrawals, and performance

This function is restricted to governance roles.

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Updates contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by reentrancy guard

  • access: Restricted to authorized roles

  • oracle: Requires fresh oracle price data

function setPoolFees(uint256 _depositFee, uint256 _withdrawalFee, uint256 _performanceFee)
    external
    onlyRole(GOVERNANCE_ROLE);

Parameters

NameTypeDescription
_depositFeeuint256New deposit fee in basis points
_withdrawalFeeuint256New withdrawal fee in basis points
_performanceFeeuint256New performance fee in basis points

updateYieldShift

Updates the YieldShift contract address

Governance-only setter for phased deployment wiring

Notes:

  • security: Validates address and restricts to governance role

  • access: Restricted to GOVERNANCE_ROLE

function updateYieldShift(address _yieldShift) external onlyRole(GOVERNANCE_ROLE);

Parameters

NameTypeDescription
_yieldShiftaddressNew YieldShift contract address

emergencyUnstake

Emergency unstake for a specific user (restricted to emergency roles)

This function is intended for emergency situations where a user's staked QEURO needs to be forcibly unstaked.

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Updates contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by reentrancy guard

  • access: Restricted to authorized roles

  • oracle: Requires fresh oracle price data

function emergencyUnstake(address user) external onlyRole(EMERGENCY_ROLE);

Parameters

NameTypeDescription
useraddressAddress of the user to unstake

pause

Pause the user pool (restricted to emergency roles)

This function is used to pause critical operations in case of a protocol-wide emergency or vulnerability.

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Updates contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by reentrancy guard

  • access: Restricted to authorized roles

  • oracle: Requires fresh oracle price data

function pause() external onlyRole(EMERGENCY_ROLE);

unpause

Unpause the user pool (restricted to emergency roles)

This function is used to re-enable critical operations after an emergency pause.

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Updates contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by reentrancy guard

  • access: Restricted to authorized roles

  • oracle: Requires fresh oracle price data

function unpause() external onlyRole(EMERGENCY_ROLE);

isPoolActive

Check if the user pool is currently active (not paused)

Returns the current pause status of the pool

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Updates contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by reentrancy guard

  • access: Restricted to authorized roles

  • oracle: Requires fresh oracle price data

function isPoolActive() external view returns (bool);

Returns

NameTypeDescription
<none>boolbool True if the pool is active, false otherwise

recoverToken

Recover accidentally sent tokens to treasury only

Recovers accidentally sent ERC20 tokens to the treasury address

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Updates contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by reentrancy guard

  • access: Restricted to authorized roles

  • oracle: Requires fresh oracle price data

function recoverToken(address token, uint256 amount) external onlyRole(DEFAULT_ADMIN_ROLE);

Parameters

NameTypeDescription
tokenaddressToken address to recover
amountuint256Amount to recover

recoverETH

Recover ETH to treasury address only

SECURITY: Restricted to treasury to prevent arbitrary ETH transfers

Notes:

  • security: Validates input parameters and enforces security checks

  • validation: Validates input parameters and business logic constraints

  • state-changes: Updates contract state variables

  • events: Emits relevant events for state changes

  • errors: Throws custom errors for invalid conditions

  • reentrancy: Protected by reentrancy guard

  • access: Restricted to authorized roles

  • oracle: Requires fresh oracle price data

function recoverETH() external onlyRole(DEFAULT_ADMIN_ROLE);

Events

UserDeposit

Emitted when a user deposits USDC and receives QEURO

Indexed parameters allow efficient filtering of events

event UserDeposit(address indexed user, uint256 usdcAmount, uint256 qeuroMinted, uint256 timestamp);

Parameters

NameTypeDescription
useraddressAddress of the user who deposited
usdcAmountuint256Amount of USDC deposited (6 decimals)
qeuroMinteduint256Amount of QEURO minted (18 decimals)
timestampuint256Timestamp of the deposit

UserWithdrawal

Emitted when a user withdraws QEURO and receives USDC

Indexed parameters allow efficient filtering of events

event UserWithdrawal(address indexed user, uint256 qeuroBurned, uint256 usdcReceived, uint256 timestamp);

Parameters

NameTypeDescription
useraddressAddress of the user who withdrew
qeuroBurneduint256Amount of QEURO burned (18 decimals)
usdcReceiveduint256Amount of USDC received (6 decimals)
timestampuint256Timestamp of the withdrawal

UserDepositTracked

Emitted when a user deposit is tracked with oracle ratio

event UserDepositTracked(
    address indexed user,
    uint256 usdcAmount,
    uint256 qeuroReceived,
    uint256 oracleRatio,
    uint256 timestamp,
    uint256 blockNumber
);

Parameters

NameTypeDescription
useraddressAddress of the user who deposited
usdcAmountuint256USDC amount deposited (6 decimals)
qeuroReceiveduint256QEURO amount received (18 decimals)
oracleRatiouint256Oracle ratio at time of deposit (scaled by 1e6)
timestampuint256Block timestamp when deposit was made
blockNumberuint256Block number when deposit was made

UserWithdrawalTracked

Emitted when a user withdrawal is tracked with oracle ratio

event UserWithdrawalTracked(
    address indexed user,
    uint256 qeuroAmount,
    uint256 usdcReceived,
    uint256 oracleRatio,
    uint256 timestamp,
    uint256 blockNumber
);

Parameters

NameTypeDescription
useraddressAddress of the user who withdrew
qeuroAmountuint256QEURO amount withdrawn (18 decimals)
usdcReceiveduint256USDC amount received (6 decimals)
oracleRatiouint256Oracle ratio at time of withdrawal (scaled by 1e6)
timestampuint256Block timestamp when withdrawal was made
blockNumberuint256Block number when withdrawal was made

QEUROStaked

Emitted when a user stakes QEURO

Indexed parameters allow efficient filtering of events

event QEUROStaked(address indexed user, uint256 qeuroAmount, uint256 timestamp);

Parameters

NameTypeDescription
useraddressAddress of the user who staked
qeuroAmountuint256Amount of QEURO staked (18 decimals)
timestampuint256Timestamp of the staking action

QEUROUnstaked

Emitted when a user unstakes QEURO

Indexed parameters allow efficient filtering of events

event QEUROUnstaked(address indexed user, uint256 qeuroAmount, uint256 timestamp);

Parameters

NameTypeDescription
useraddressAddress of the user who unstaked
qeuroAmountuint256Amount of QEURO unstaked (18 decimals)
timestampuint256Timestamp of the unstaking action

StakingRewardsClaimed

Emitted when staking rewards are claimed by a user

Indexed parameters allow efficient filtering of events

event StakingRewardsClaimed(address indexed user, uint256 rewardAmount, uint256 timestamp);

Parameters

NameTypeDescription
useraddressAddress of the user who claimed rewards
rewardAmountuint256Amount of QEURO rewards claimed (18 decimals)
timestampuint256Timestamp of the reward claim

YieldDistributed

Emitted when yield is distributed to stakers

OPTIMIZED: Indexed timestamp for efficient time-based filtering

event YieldDistributed(uint256 totalYield, uint256 yieldPerShare, uint256 indexed timestamp);

Parameters

NameTypeDescription
totalYielduint256Total amount of yield distributed (18 decimals)
yieldPerShareuint256Amount of yield per staked QEURO share (18 decimals)
timestampuint256Timestamp of the yield distribution

PoolParameterUpdated

Emitted when pool parameters are updated

OPTIMIZED: Indexed parameter name for efficient filtering by parameter type

event PoolParameterUpdated(string indexed parameter, uint256 oldValue, uint256 newValue);

Parameters

NameTypeDescription
parameterstringName of the parameter updated
oldValueuint256Original value of the parameter
newValueuint256New value of the parameter

ETHRecovered

Emitted when ETH is recovered to the treasury

event ETHRecovered(address indexed to, uint256 indexed amount);

Parameters

NameTypeDescription
toaddressRecipient address
amountuint256Amount of ETH recovered

Structs

UserInfo

User information data structure

Stores all information about a user's deposits, stakes, and rewards

Used for user management and reward calculations

OPTIMIZED: Timestamps and amounts packed for gas efficiency

struct UserInfo {
    uint128 qeuroBalance; // QEURO balance from deposits (18 decimals, max ~340B)
    uint128 stakedAmount; // QEURO amount currently staked (18 decimals, max ~340B)
    uint128 pendingRewards; // Pending staking rewards in QEURO (18 decimals, max ~340B)
    uint128 unstakeAmount; // Amount being unstaked (18 decimals, max ~340B)
    uint96 depositHistory; // Total historical deposits in USDC (6 decimals, max ~79B USDC)
    uint64 lastStakeTime; // Timestamp of last staking action (until year 2554)
    uint64 unstakeRequestTime; // Timestamp when unstaking was requested (until year 2554)
}

UserDepositInfo

User deposit information with oracle ratio tracking

Stores individual deposit records with oracle ratios for detailed analytics

Used for audit trails and historical analysis

struct UserDepositInfo {
    uint128 usdcAmount; // USDC amount deposited (6 decimals, max ~340B USDC)
    uint128 qeuroReceived; // QEURO amount received (18 decimals, max ~340B QEURO)
    uint64 timestamp; // Block timestamp when deposit was made (until year 2554)
    uint32 oracleRatio; // Oracle ratio at time of deposit (scaled by 1e6, max ~4.2B)
    uint32 blockNumber; // Block number when deposit was made (until year 2106)
}

UserWithdrawalInfo

User withdrawal information with oracle ratio tracking

Stores individual withdrawal records with oracle ratios for detailed analytics

Used for audit trails and historical analysis

struct UserWithdrawalInfo {
    uint128 qeuroAmount; // QEURO amount withdrawn (18 decimals, max ~340B QEURO)
    uint128 usdcReceived; // USDC amount received (6 decimals, max ~340B USDC)
    uint64 timestamp; // Block timestamp when withdrawal was made (until year 2554)
    uint32 oracleRatio; // Oracle ratio at time of withdrawal (scaled by 1e6, max ~4.2B)
    uint32 blockNumber; // Block number when withdrawal was made (until year 2106)
}