[ARFC] Onboard Strata srUSDe PT tokens to V3 Core Instance

srUSDe (Strata) technical analysis


Summary

This is a technical analysis of all the smart contracts of the srUSDe asset and its main dependencies.

Disclosure: This is not an exhaustive security review of the asset like the ones done by Strata Team, but an analysis from an Aave technical service provider on different aspects we consider critical to review before a new type of listing. Consequently, like with any security review, this is not an absolute statement that the asset is flawless, only that, in our opinion, we don’t see significant problems with its integration with Aave, apart from different trust points.


Analysis

Senior USDe (srUSDe) is a yield-bearing token backed by USDe and represents the senior risk tranche within Strata’s system, which is composed of senior and junior tranches. The senior tranche receives a guaranteed yield tied to the benchmark rate, with uncapped upside to sUSDe APY, and pays a risk premium to the junior tranche for protection. Junior receives the base yield from sUSDe plus the risk premium paid by the senior tranche, adjusted by the TVL ratio, and absorbs shortfalls if sUSDe APY drops below the benchmark. Users can deposit USDe, sUSDe, and pUSDe to receive srUSDe. While they can redeem sUSDe immediately, they must wait for Ethena’s unstaking period to redeem USDe.



For the context of this analysis, our focus has been on the following aspects, critical for the correct and secure integration with Aave:

  • A recommendation of pricing strategy to be used in the integration asset <> Aave.
  • Any miscellaneous aspect of the code that can be considered important.
  • Analysis of the access control (ownerships, admin roles) and the nature of the entities involved in the system. Regarding the table permissions’ holders and their criticality/risk, it is done following these guidelines:
Criticality Description
CRITICAL Usually super-admin functionality: it can compromise the system by completely changing its fundamentals, leading to loss of funds if misused or exploited. E.g. proxy admin, default admin
HIGH It can control several parts of the system with some risk of losing funds. E.g., general owners or admin roles involved in the flow of funds
MEDIUM It can cause malfunction and/or minor financial losses if misused or exploited. E.g., fee setter, fee recipient addresses
LOW It can cause system malfunctions but on non-critical parts without meaningful/direct financial losses. E.g., updating descriptions or certain non-critical parameters.

Risk Description
:green_circle: The role is controlled via a mechanism we consider safe, such as on-chain governance, a timelock contract, or setups involving multi-sigs under certain circumstances.
:yellow_circle: The role is controlled in a way that could expose the system and users to some risk depending on the actions it can control.
:red_circle: The role is controlled via a clearly non-secure method, representing risks for the system and users.

General points

  • The Strata system relies on a set of upgradable contracts, with main dependencies from OZ for access control, tokenization, math, and upgradability. It also uses the PRBMath library.

  • The srUSDe and jrUSDe are receipt tokens that implement the OZ ERC4626 pattern.

  • For proxies, it uses OZ Transparent pattern.

  • The system upgradability is controlled by a 2-day Timelock.

  • General access control is managed via the Access Controlled contract, which is a wrapper around the OZ access control. The admin is shared between timelocks and a safe wallet.


Contracts

The following is a non-exhaustive overview of the main smart contracts involved with srUSDe.



srUSDe (Tranche)

The Senior tranche srUSDe is the core system’s contract. It implements the OZ ERC4626, which users interact with to mint and burn srUSDe shares by depositing USDe and sUSDe. It forwards deposits and withdrawals to StrataCDO, orchestrated via the sUSDeStrategy. The Junior tranche (jrUSDe) uses the same contract infrastructure (Tranche) as srUSDe. It is an upgradable Transparent Proxy with ownable access control via the AccessControlled contract.

Permission Owner functions Criticality Risk
Upgradable admin: Proxy Admin2-day Timelock upgradeAndCall CRITICAL :green_circle:
owner: 2-day Timelock setAccessControlManager, setTwoStepConfigManager HIGH :green_circle:
StrataCDO configure HIGH :green_circle:

  • Access Control
    • The owner can configure the AccessControlManager and TwoStepConfigManager addresses via setAccessControlManager(address) and setTwoStepConfigManager(address) functions respectfully.

    • The StrataCDO contract can call configure(), which sets the maximum allowance of the underlying assets toward the sUSDeStrategy contract. This is called once.

  • Deposit and Redemptions
    • All deposit and redemption operations first updates the accounting index via cdo.updateAccounting(), syncing the total assets under the strategy’s control. After the inflow/outflow of assets into the strategy, the cdo adjusts the NAV for Senior and Junior tranches via the accounting.updateBalanceFlow() method.

    • Users can deposit USDe and sUSDe via the deposit(token, tokenAmount, receiver) function. Internally, it calculates the user’s srUSDe shares via strategy.convertToAssets(token, tokenAmount), mints them, and transfers them to the receiver.

    • The deposit assets flow to a Strategy contract where they are transformed into sUSDe.

    • Users can redeem sUSDe instantly via the redeem(token, shares, receiver, owner) function. Internally, it calculates the baseAssets via previewRedeem(shares) and uses them to calculate the assets strategy.convertToTokens(token, baseAssets), burns the owner’s srUSDe shares and transfers sUSDe to the ERC20Cooldown contract. Since the cooldown period for withdraws of sUSDe is zero, the ERC20Cooldown contract transfers the sUSDe to the receiver immediately.

    • Users who want to redeem USDe are subject to Ethena’s unstaking period. In that case, the sUSDe goes to the UnstakeCooldown contract, which handles the unstaking period, and later users can finalize and claim USDe.

  • Exchange Rate
    • The exchange rate of srUSDe <> USDe is calculate through the StrataCDO, Accounting and sUSDeStrategy contracts. The system uses two distinct exchange rates: one for processing new deposits and the other for finalizing redemptions.

      • Deposit exchange rate: Relies on the previewDeposit(assets) function, which is calculated using the standard ERC4626 pattern of assets * totalSupply() / totalAssets().

      • Redemption exchange rate: Relies into the previewRedeem(shares) function, which takes a 0.025% fee from the srUSDe shares and then uses the standard ERC4626 of shares * totalAssets() / totalSupply().

      • The totalAssets() is fetched from cdo.totalAssets(), which internally queries the totalUSDe held by the sUSDeStrategy contract and extracts the srUSDe portion from accounting.totalAssets(totalUSDe) function, which splits the totalUSDe into srUSDe and jrUSDe portions.

      • It’s important to note that totalUSDe is derived from the total sUSDe shares held by the Strategy, sUSDe.balanceOf(strategy), and the sUSDe <> USDe exchange rate, sUSDe.convertToAssets(shares).

      • By relying on balanceOf(), the Strata system is not fully donation-resistant, meaning that sUSDe donations to the Strategy can change the general totalUSDe value.

      • Given the system dynamics, where the Accounting contract splits the totalUSDe in portions, the Junior tranche receives all donation because the Senior tranche

      • Given the system dynamics, in a scenario where a large amount of sUSDe is donated to the Strategy, the Junior tranche would absorb the entire donation because the Senior tranche’s totalAssets gains are capped at the Senior target APR (set via risk params).


AccessControlManager

The AccessControlManager contract coordinates access control for the Strata system. It’s a non-upgradable wrapper of the OZ Access control.

Role Function Criticality Risk
DEFAULT_ADMIN_ROLE: 2-day Timelock, 1-day Timelock grantRole, revokeRole CRITICAL :green_circle:

  • Access Control
    • The DEFAULT_ADMIN_ROLE manages all role assignments in the Strata system through the grantRole(role, address) function. It can also revoke roles from accounts using the revokeRole(role, address) function.

StrataCDO

The StrataCDO contract is the core orchestrator of the Strata system. It orchestrates the Senior and Junior tranches, accounting, and sUSDe strategy; Deposits and withdrawals are routed through the CDO. It enforces tranche-level pause states and exit fees. It is an upgradeable OZ Transparent Proxy controlled via an ownable, role-based access control implemented by the AccessControlled contract.

Role Function Criticality Risk
upgrade admin: ProxyAdmin2-day Timelock upgradeAndCall CRITICAL :green_circle:
owner: 2-day Timelock configure, setAccessControlManager, setTwoStepConfigManager CRITICAL :green_circle:
srUSDe, jrUSDe accrueFee, updateAccounting, deposit, withdraw HIGH :green_circle:
RESERVE_MANAGER_ROLE : 1-day timelock reduceReserve, distributeReserve, setReserveTreasury HIGH :green_circle:
PAUSER_ROLE: Safe 2-of-3 setActionStates, setJrtShortfallPausePrice MEDIUM :green_circle:
TwoStepConfigManager setExitFees MEDIUM :green_circle:

  • Access Control
    • The owner can configure the AccessControlManager and TwoStepConfigManager addresses via setAccessControlManager(address) and setTwoStepConfigManager(address) functions, respectively.

    • The owner can call configure(), which calls the configure() functions in the Senior and Junior tranche contracts. This is called once after deployment.

    • Senior and Junior tranches can call deposit() and withdraw() functions, which internally orchestrate the inflow and outflow of assets to the sUSDeStrategy contract. During these operations, updateAccounting() is called, and accrueFee() is called only during withdrawals.

    • The RESERVE_MANAGER_ROLE can configure the treasury address via the setReserveTreasury(address) function, redistribute reserve back to tranche TVL via the distributeReserve(uint jrAmountIn, uint srAmountIn) function, or withdraw protocol reserve to the treasury address via the reduceReserve(token, amount) function.

    • The PAUSER_ROLE can pause and resume deposits and redemptions in the Senior and Junior tranches via the setActionStates(tranche, isDepositEnabled, isWithdrawEnabled) function. It can also pause Junior deposits via the setJrtShortfallPausePrice(shortfallPrice) function; The shortfallPrice must be below the current Junior sUSDe share price.


sUSDeStrategy

The Strategy manages USDe stakes into sUSDe during CDO deposits, holds sUSDe, and fulfills withdrawals via cooldown contracts for each tranche. It is an upgradeable OZ Transparent Proxy controlled via an ownable, role-based access control implemented by the AccessControlled contract.

Role Function Criticality Risk
upgrade admin: ProxyAdmin2-day Timelock upgradeAndCall CRITICAL :green_circle:
owner: 2-day Timelock setAccessControlManager, setTwoStepConfigManager HIGH :green_circle:
UPDATER_STRAT_CONFIG_ROLE: 1-day Timelock setCooldowns HIGH :green_circle:
StrataCDO deposit, withdraw, reduceReserve HIGH :green_circle:

  • Access Control
    • The owner can configure the AccessControlManager and TwoStepConfigManager addresses via setAccessControlManager(address) and setTwoStepConfigManager(address) functions respectfully.

    • The UPDATER_STRAT_CONFIG_ROLE can adjusts and disable tranche-specific sUSDe cooldowns via the setCooldowns(uint sUSDeCooldownJrt, uint sUSDeCooldownSrt) function.

    • StrataCDO contract can move assets into/out of the strategy through the deposit(tranche, token, amount, baseAssets, owner) and withdraw(tranche, token, amount, baseAssets, sender, receiver) methods and the reserve via the reduceReserve(token, amount, receiver) method.


Accounting

The Accounting contract tracks the tranches’ TVL, calculates Net Asset Value (NAV), and implements the so-called Dynamic Yield Split (DYS) mechanism, which splits NAV between Senior and Junior tranches, based on the risk parameters and benchmark rate set in the contract. It is an upgradeable OZ Transparent Proxy controlled via an ownable, role-based access control implemented by the AccessControlled contract.

Role Function Criticality Risk
upgrade admin: ProxyAdmin2-day timelock upgradeAndCall CRITICAL :green_circle:
owner: 2-day timelock setAprPairFeed, setReserveBps, setFeeRetentionBps, setMinimumJrtSrtRatio, setMinimumJrtSrtRatioBuffer HIGH :green_circle:
UPDATER_STRAT_CONFIG_ROLE: 1-day Timelock setRiskParameters HIGH :green_circle:
UPDATER_FEED_ROLE : Safe 2-of-3 onAprChanged MEDIUM :green_circle:
StrataCDO updateAccounting, updateBalanceFlow, reduceReserve, accrueFee MEDIUM :green_circle:

  • Access Control
    • The owner can configure the AprPairFeed contract using the setAprPairFeed(address) method.

    • The owner can adjust the protocol gains and the fee allocation for each tranche via the setReserveBps(uint bps) and setFeeRetentionBps(uint jrBps, uint srBps) methods, respectively. The owner can also adjust the minimum ratio and buffer between Junior and Senior tranches (the ratio at which Jr withdrawals are blocked and deposits are halted) by calling the setMinimumJrtSrtRatio(uint ratio) and setMinimumJrtSrtRatioBuffer(uint ratio) functions.

    • The UPDATER_STRAT_CONFIG_ROLE can configure risk parameters used by the NAV calculation via the setRiskParameters(x, y, k) function, where:

      • x: Minimum risk premium.
      • y: additional premium applied on top of x.
      • k: Exponential scaling factor controlling premium growth.
    • The UPDATER_FEED_ROLE can trigger an update in the srtTargetIndex by fetching new APRs via the onAprChanged() function.

    • The strataCDO calls the updateAccounting(), updateBalanceFlow(), and accrueFee() methods during the assets’ inflow/outflow (already explained in the StrataCDO).


AprPairFeed

The AprPairFeed contract aggregates base and target APR data, checking for pushed updates or pulling from a provider when stale. It is primarily used by the Accounting contract during asset inflows/outflows to update the Senior and Junior NAVs. It is an upgradeable OZ Transparent Proxy controlled via an ownable, role-based access control implemented by the AccessControlled contract.

Role Function Criticality Risk
upgrade admin: ProxyAdmin2-day Timelock upgradeAndCall CRITICAL :green_circle:
owner: 2-day Timelock setProvider, setRoundStaleAfter HIGH :green_circle:
UPDATER_FEED_ROLE: Safe 2-of-3 updateRoundData (pull/push) MEDIUM :green_circle:

  • Access Control
    • The owner can set the provider contract, from which the contract pulls data via the setProvider(address) method. The owner can also configure the time duration after which a round is considered stale via the setRoundStaleAfter(uint value) function.

    • The UPDATER_FEED_ROLE can pull APR data via the updateRoundData() or push off-chain APR data via the updateRoundData(int aprTarget, int aprBase, uint timestamp) function. Both fall back to an internal function that checks whether the update is not stale and whether both APRs are within the acceptable bounds (-50% and 200%).


AaveAprPairProvider

The AaveAprPairProvider contract is a stateless APR source that computes the target APR from Aave’s USDC and USDT reserves data, and the base APR from sUSDe’s vesting. It is primarily used by the AprPairFeed contract and has no privileged access controls.


ERC20Cooldown

The ERC20Cooldown holds sUSDe during cooldown-based withdrawals and releases funds after the unlock time. It is an upgradeable OZ Transparent Proxy controlled via an ownable, role-based access control implemented by the AccessControlled contract.

Role Function Criticality Risk
upgrade admin: ProxyAdmin2-day Timelock upgradeAndCall CRITICAL :green_circle:
owner: 2-day Timelock setAccessControlManager, setTwoStepConfigManager HIGH :green_circle:
COOLDOWN_WORKER_ROLE: sUSDeStrategy transfer, setCooldownDisabled HIGH :green_circle:

  • Access Control
    • The owner can configure the AccessControlManager and TwoStepConfigManager addresses via setAccessControlManager(address) and setTwoStepConfigManager(address) functions respectfully.

    • Cooldowns are enabled or disabled by calling the setCooldownDisabled(token, bool) function, which is initiated via the strategy contract. Currently, there’s no cooldown for sUSDe withdrawals, so after the strategy calls transfer(), it immediately transfers the assets to the user.


UnstakeCooldown

UnstakeCooldown manages token-specific unstake handlers via per-user clone proxies and finalizes requests after underlying cooldowns; it is upgradeable via TransparentUpgradeableProxy with AccessControlled roles and a CRITICAL ProxyAdmin.

Role Function Criticality Risk
upgrade admin: ProxyAdmin2-day Timelock upgrade CRITICAL :green_circle:
owner: 2-day Timelock setImplementations, setAccessControlManager, setTwoStepConfigManager HIGH :green_circle:
COOLDOWN_WORKER_ROLE: sUSDeStrategy transfer HIGH :green_circle:

  • Access Control
    • The owner can configure the AccessControlManager and TwoStepConfigManager addresses via setAccessControlManager(address) and setTwoStepConfigManager(address) functions respectfully.

    • The owner can configure token implementations that handle the unstake from sUSDe via the setImplementations(token, address) function.

    • When a user requests a USDe redemption, the strategy calls transfer(), and the UnstakeCooldown initiates the sUSDe unstake from Ethena. After the unstake period finishes, the user calls finalize(), which transfers USDe to the user.


Pricing strategy

Although srUSDe is not initially planned to be listed on Aave, it’s important to provide our recommendation, as the DAO is considering listing its PT token. Our suggestion is to price srUSDe using a CAPO adapter, applying the srUSDe <> USDe redemption exchange rate along with the USDT stable CAPO feed.

This recommendation follows the USDe price strategy across Aave instances.

We also must highlight that the Strata system is not donation-resistant, and sUSDe can manipulate the underlying assets. However, as explained in the exchange rate section, given the split dynamics, the Senior tranche caps its total assets at the target APR, and donations are redirected to the Junior tranche’s total assets. Still, we recommend not listing this asset (and definitely not jrUSDe) as collateral without a deep review of the analysis.


Miscellaneous

  • The system has undergone several security reviews by Quantstamp, Cyfrin and Guardian. They can be found in the Strata documentation here.

Conclusion

We believe srUSDe has no issues with Aave integration and no major blockers for listing.

2 Likes