Skip to content

Functions

Note

Collateral in the locker lives in epoch buckets. Every function that changes a position first calls _updateUnlocked to mature any buckets whose epoch has passed, then _updateReward to settle the caller's share of the reward stream against their debt. Read Unlock Scheduling before using requestUnlock and withdrawUnlocked.

Everything here is whenNotPaused

Every state-changing entry point on this page — including repay and withdrawUnlocked — is gated by the pause. PAUSER_ROLE can pause; only the owner can unpause.


Collateral

deposit

deposit(uint256 _amount)

Summary Pulls _amount RAAC from the caller, locks it into veRAAC for lockDurationEpochs, and records an epoch bucket maturing at the resulting week boundary. If the caller's most recent bucket already sits at that epoch, the amounts merge.

Guarded Method Callable by any address. Subject to whenNotPaused, nonReentrant and a non-zero amount check.

Parameters

Name Type Description
_amount uint256 RAAC to deposit; must clear veRAAC's minLockAmount

Emits — Deposit(address indexed depositor, address indexed recipient, uint256 amount)

Reverts

Error Condition
NonZeroValue() _amount == 0
AmountBelowMinimum() propagated from veRAAC when below minLockAmount
Typescript / ethers
await raac.approve(locker.target, parseUnits("1000", 18));
await locker.deposit(parseUnits("1000", 18));
Source code
function deposit(uint256 _amount) external override checkNotZeroValue(_amount) nonReentrant whenNotPaused {
    _updateUnlocked(msg.sender);
    // pull token from user
    raac.safeTransferFrom(msg.sender, address(this), _amount);
    _deposit(msg.sender, _amount);
}

depositOnBehalfOf

depositOnBehalfOf(address _user, uint256 _amount)

Summary Same as deposit, but credits the position to _user while pulling the RAAC from the caller. This is how a gauge converts a user's claimed RAAC emissions straight into a locker position.

Guarded Method Callable by _user themselves, or by any address holding ON_BEHALF_OF_ROLE. Subject to whenNotPaused and nonReentrant.

Parameters

Name Type Description
_user address Account credited with the position
_amount uint256 RAAC to deposit, pulled from msg.sender

Emits — Deposit(address indexed depositor, address indexed recipient, uint256 amount)

Reverts — Unauthorized() when the caller is neither _user nor a role holder.

No zero-amount guard

Unlike deposit, this function carries no checkNotZeroValue modifier. A zero amount reaches veRAAC, which rejects it.


requestUnlock

requestUnlock(uint256 _amount)

Summary Reserves _amount of the caller's locked RAAC for withdrawal, consuming soonest-maturing buckets first and partial-reserving the boundary bucket. Reserved collateral stops backing debt immediately; the open remainder of each bucket continues to auto-relock.

If reserving only part of a bucket would leave an open remainder below veRAAC's minLockAmount, the whole bucket is reserved instead — which means the amount actually scheduled can exceed _amount.

Guarded Method Callable by any depositor. Subject to whenNotPaused, nonReentrant and a non-zero amount check.

Parameters

Name Type Description
_amount uint256 RAAC to schedule for unlock

Emits — Unlock(address indexed account, uint256 amount) carrying the amount actually scheduled

Reverts

Error Condition
NonZeroValue() _amount == 0
InsufficientCollateral() reserving would leave unreserved locked below 2 × debt
InsufficientToUnlock() scheduled less than _amount, or overshot it by more than minLockAmount

Matured buckets cannot be reserved

_scheduleUnlock skips any bucket whose unlockEpoch <= currentEpoch. Collateral already past its epoch boundary has auto-relocked into a new bucket and must be reserved there.


withdrawUnlocked

withdrawUnlocked()

Summary Withdraws the caller's matured reserved RAAC. Before paying out, the function computes how much collateral the outstanding debt still requires and relocks the shortfall through _deposit, transferring only the safe remainder.

Guarded Method Callable by any depositor with matured reservations. Subject to whenNotPaused and nonReentrant.

Emits

  • Withdraw(address indexed account, uint256 amount) — for the payout leg
  • Deposit(...) — when part of the amount is relocked

Reverts

Error Condition
InsufficientUnlocked() nothing has matured
AmountBelowMinimum() propagated from veRAAC when the relock leg is below minLockAmount

A dust relock can block the withdrawal entirely

If the amount that must be relocked is smaller than veRAAC's minLockAmount, the inner lock reverts and the whole withdrawal fails. The position self-heals as the reward stream repays the debt, and repaying manually clears it immediately. This is accepted — see Design Trade-offs.


previewWithdraw

previewWithdraw(address _account) → (uint256 payout, uint256 relock)

Summary Projects the split withdrawUnlocked would produce at the account's current debt, using the identical _splitWithdraw helper so the preview always matches the outcome. Returns (0, 0) when nothing has matured.


Debt

borrow

borrow(uint256 _amount, bool _depositMaturityVault)

Summary Mints _amount of leRAAC to the caller, or deposits it into the Maturity Vault on their behalf. Accrued rewards are consumed first and do not become debt; only the shortfall increases totalDebt and is health-checked against unreserved collateral.

Guarded Method Callable by any depositor. Subject to whenNotPaused, nonReentrant and a non-zero amount check.

Parameters

Name Type Description
_amount uint256 leRAAC to borrow
_depositMaturityVault bool true routes the minted leRAAC into the maturity vault for the caller

Emits — Borrow(address indexed caller, address indexed recipient, uint256 amount)

Reverts

Error Condition
NonZeroValue() _amount == 0
InsufficientCollateral() unreserved locked would fall below 2 × debt

Borrowing after a reservation is allowed

Reserved collateral is netted out of the health check, but a position can still end up undercollateralised later as buckets mature. That is deliberate — see Design Trade-offs.


repay

repay(uint256 _leRAACAmount)

Summary Repays outstanding debt by burning the caller's leRAAC. The amount is capped at the caller's debt. A repayFeePercentage cut is transferred to the treasury as leRAAC and only the remainder is burned and deducted from the debt.

Guarded Method Callable by any borrower. Subject to whenNotPaused, nonReentrant and a non-zero amount check.

Parameters

Name Type Description
_leRAACAmount uint256 leRAAC to repay; capped at outstanding debt

Emits — Repay(address indexed account, uint256 amount) carrying the net amount burned

A non-zero repay fee makes full repayment impossible

Because the fee is taken out of the repayment rather than charged on top, only amount - fee ever reduces the debt. The parameter is held at 0 in production for this reason. See Design Trade-offs.

Silent no-op when debt-free

The whole body is wrapped in if (_totalDebt > 0). Calling repay with no debt succeeds, emits nothing and moves no tokens.


Rewards

harvest

harvest(address _recipient, uint256 _minimunOut) → uint256

Summary Claims every veRAAC reward token, swaps non-RAAC rewards to the intermediate token and then to RAAC through the Zap, applies the treasury fee and harvest bounty, and distributes the remainder to depositors and the maturity vault.

Guarded Method Requires HARVEST_ROLE. Subject to whenNotPaused.

Parameters

Name Type Description
_recipient address Receives the harvest bounty
_minimunOut uint256 Minimum RAAC out of the Zap leg

Returns — total RAAC harvested, pre-fees, including RAAC-denominated rewards.

Emits

  • Harvest(address indexed caller, uint256 reward, uint256 platformFee, uint256 harvestBounty)
  • ClaimRewardClaimed(address indexed token, uint256 amountClaimed) / ClaimRewardFailed(address indexed token, string reason) per token

Reverts

Error Condition
InvalidLength() claim results do not match the reward-token list
InsufficientOutput() Zap output below _minimunOut
BotLockerHarvestError() bot-locker distribution failed with an unrecognised reason

_minimunOut does not cover RAAC-denominated rewards

The check runs on the swapped amount before direct RAAC rewards are added. Rewards already in RAAC bypass the Zap and are outside the slippage bound.


donate(uint256 _amount)

Summary Pulls RAAC from the caller and pushes it straight into the reward stream, repaying depositor debt without going through a harvest. Fees and the bounty are not applied.

Guarded Method Requires DEFAULT_ADMIN_ROLE. Subject to whenNotPaused, nonReentrant and a non-zero amount check.


Gauge Operations

depositToGauge

depositToGauge(address _token, address _gauge, uint256 _amount)

Summary Pulls LP tokens from the caller and stakes them into a gauge from the locker's address, so the locker's boost applies. The token is checked against veRAAC's reward-token list and rejected if it appears there.

Guarded Method — BOOSTER_ROLE, whenNotPaused, nonReentrant, non-zero amount.

Emits — DepositedToGauge(address indexed gauge, uint256 amount, address token)

Reverts — InvalidToken() if _token is a registered veRAAC reward token.

No fee-on-transfer support

The staked amount is the requested amount, not the observed balance delta.


withdrawFromGauge

withdrawFromGauge(address _token, address _gauge, uint256 _amount, uint256 _minOut, address _to)

Summary Withdraws _amount of LP tokens from a gauge and forwards them to _to.

Guarded Method — BOOSTER_ROLE, whenNotPaused, nonReentrant, non-zero amount.

Reverts — ZeroAddress() for a zero _to; InsufficientOutput() when _amount < _minOut.

_minOut compares against the requested amount

The gauge withdrawal is assumed to return exactly _amount, so the check is _amount < _minOut rather than a comparison against an observed balance delta.


claimRewardFor

claimRewardFor(address _user, uint256 _amount, address _gauge, address _token) → uint256

Summary Calls claimOnBehalfOf on a gauge so a user's rewards are claimed through the locker.

Guarded Method — BOOSTER_ROLE, whenNotPaused, non-zero amount.

Emits — RewardClaimedFor(address indexed user, address gauge, address token, uint256 claimedAmount)


Operations

processVaultExpiredLocks

processVaultExpiredLocks()

Summary Matures the locker's own veRAAC position: advances global epoch accounting, remaps expired lock ends, withdraws whatever veRAAC has matured, and relocks everything above the liquidity buffer.

The buffer retained is totalUnlockedGlobal + pendingCumulatedAmount. The excess is relocked only if it clears veRAAC's minLockAmount.

Guarded Method Requires the keeper whitelist (isKeeper). Subject to whenNotPaused and nonReentrant.

Emits — VaultExpiredLocksProcessed(uint256 amount)

Never blocks on an empty maturity

veRAAC.withdraw() reverts when nothing has expired, so the call is wrapped in a try and returns early instead of failing the keeper's transaction.


updateGlobals

updateGlobals()

Summary Permissionless. Advances totalLockedGlobal and totalUnlockedGlobal across every scheduled epoch end that has passed. Called internally by _distribute and processVaultExpiredLocks; exposed so anyone can keep global accounting current.


Voting

Function Gate Effect
voteGauge(controller, gauge, weight) DELEGATE_ROLE casts the pooled position's gauge weight vote
voteGovernance(governance, proposalId, support) DELEGATE_ROLE casts a governance vote, returns the power used
removePowerFromGauge(controller, gauge) DELEGATE_ROLE clears the locker's weight from a retired gauge
addGauge(gauge) OPERATOR_ROLE grants ON_BEHALF_OF_ROLE to a gauge

All four revert with ZeroAddress() on a zero argument; the first three are whenNotPaused.


Administration

Function Gate Validation
pause() PAUSER_ROLE —
unpause() onlyOwner —
updateWhitelist(keeper, status) onlyOwner none
updateZap(zap) onlyOwner non-zero
updateTreasury(treasury) onlyOwner non-zero
updateBotLocker(locker) onlyOwner non-zero
updateCleverFeeRecipient(recipient) onlyOwner non-zero
updateIntermediateRewardToken(token) onlyOwner non-zero, and the Zap must have a route from the new token to RAAC and from every reward token to it
updateRepayFeePercentage(pct) onlyOwner <= MAX_REPAY_FEE (10 %)
updateHarvestBountyPercentage(pct) onlyOwner <= MAX_HARVEST_BOUNTY (10 %)
updateFeeShares(bots, clever, treasury, total) onlyOwner total <= MAX_TREASURY_FEE (50 %) and the three shares must sum to total
toggleMaxDistributions(enable) DEFAULT_ADMIN_ROLE —
setMaxHarvestDistribution(n) DEFAULT_ADMIN_ROLE 1 <= n <= 100

setMaxHarvestDistribution bounds a count, not an amount

Despite the name, maxDistribution caps the number of veRAAC distributions processed per reward token in one harvest, which is what keeps harvest inside the block gas limit. It only applies while toggleMaxDistributions(true) is set.


Views

Function Returns Notes
getUserInfo(account) 5 × uint256 totalDeposited, totalPendingUnlocked, totalUnlocked, totalBorrowed, totalReward — simulates maturity and reward settlement, so it is current without a write
checkAccountHealth(account) bool false means unreserved collateral no longer covers 2 × debt
previewWithdraw(account) (payout, relock) mirrors withdrawUnlocked exactly
getUserLocks(account) EpochUnlockInfo[] future buckets only; matured ones are excluded
poolLockedUnderlying() uint256 reads veRAAC.lockedBalanceOf(locker) — authoritative, drift-free
totalRaacInPool() uint256 raw RAAC balance held by the locker
getCurrentEpoch() uint256 block.timestamp / 7 days
userInfo(account) struct fields raw storage; does not simulate maturity — prefer getUserInfo

userInfo is raw, getUserInfo is settled

The public userInfo mapping returns stored values that may be stale by several epochs. Integrators should read getUserInfo, which replays maturity and reward settlement in memory.


Data Structures

EpochUnlockInfo

Field Type Description
pendingUnlock uint128 total RAAC in this bucket
reservedAmount uint128 portion reserved for withdrawal; 0 = fully open, == pendingUnlock = fully reserved
unlockEpoch uint64 week index at which the bucket matures

UserInfo

Field Type Description
totalDebt uint128 outstanding leRAAC debt
rewards uint128 accrued rewards not yet spent against debt
rewardPerSharePaid uint256 reward-per-share checkpoint
totalLocked uint112 RAAC currently locked
totalUnlocked uint112 matured reserved RAAC awaiting withdrawal
nextUnlockIndex uint32 cursor past consumed buckets
lastProcessedEpoch uint64 last epoch settled for this account
pendingUnlockList EpochUnlockInfo[] the buckets

Errors

Error Meaning
NonZeroValue() a zero amount was supplied
Unauthorized() caller lacks the keeper whitelist or ON_BEHALF_OF_ROLE
InsufficientCollateral() the 2 × debt health check failed
InsufficientToUnlock() the scheduled reservation missed the requested amount
InsufficientUnlocked() nothing matured to withdraw
InsufficientOutput() swap or gauge withdrawal below the minimum
FeeTooLarge() a fee parameter exceeded its cap
FeeSharesNotMatchingTreasuryFee() the three fee shares do not sum to the treasury fee
NoRoutesFound() the Zap has no route for a reward token
InvalidToken() a veRAAC reward token was passed to depositToGauge
InvalidLength() claim results did not match the reward-token list
LockParamsMismatch() veRAAC's epoch duration or max lock epochs did not match at initialize
BotLockerHarvestError() bot-locker distribution reverted with an unrecognised reason
ZeroAddress() / InvalidAmount() / InvalidAddress() argument validation