Spectra - hunter_w3b's results

A permissionless interest rate derivatives protocol on Ethereum.

General Information

Platform: Code4rena

Start Date: 23/02/2024

Pot Size: $36,500 USDC

Total HM: 2

Participants: 39

Period: 7 days

Judge: Dravee

Id: 338

League: ETH

Spectra

Findings Distribution

Researcher Performance

Rank: 4/39

Findings: 1

Award: $414.48

🌟 Selected for report: 1

πŸš€ Solo Findings: 0

Findings Information

🌟 Selected for report: hunter_w3b

Also found by: 0xbrett8571, DarkTower, Myd, ZanyBonzy, aariiif

Labels

analysis-advanced
grade-a
selected for report
sufficient quality report
A-01

Awards

414.4831 USDC - $414.48

External Links

Analysis - Spectra Contest

Spectra-Protocol

Description overview of Spectra Contest

Spectra is a permissionless interest rate derivatives protocol for DeFi. It allows users to split the yield generated by an Interest Bearing Token (IBT) from the principal asset.

Key Features:

  • Yield Tokenization: Users can deposit IBTs into the protocol and receive Principal Tokens (PT) and Yield Tokens (YT) in return. The PT represents the principal asset, while the YT represents the yield generated by the IBT.
  • Yield Trading: Holders of YT can claim the yield generated by the corresponding deposited IBTs during the time they hold the YT. This allows users to speculate on the evolution of DeFi interest rates, hedge risk on passive revenue, or provide liquidity to the derivatives layer.

Benefits:

  • Enables new applications and use cases in the DeFi ecosystem.
  • Allows users to access yield without having to wait for maturity.
  • Provides opportunities for speculation and risk hedging.

System Overview

High-level System Overview

Spectra

Scope

  1. tokens

    • PrincipalToken.sol: The PrincipalToken contract is an ERC-20 token that represents a principal token (PT) issued by a vault. The vault holds an Interest Bearing Token (IBT) of a specific underlying asset. PTs represent a claim on the underlying asset held by the vault, plus any yield generated by the IBT.

      • Key Features

        • Deposit and Withdraw: Users can deposit assets into the vault to mint PTs, or withdraw assets by redeeming PTs.
        • Yield Generation: PTs generate yield from the IBT held by the vault. Users can claim this yield in IBT or the underlying asset.
        • Fees: The contract charges fees for tokenization (depositing assets) and yield claiming.
        • Interest Bearing Token (IBT): The vault holds an IBT, which is an ERC-4626 token representing a claim on the underlying asset and any interest earned on it.
        • Yield Token (YT): The contract deploys a YT, which is an ERC-20 token that represents the yield generated by the IBT.
      • Other Notable Features

        • Rates: The contract tracks the PT rate (PT price in asset) and IBT rate (IBT price in asset).
        • Maturity: The contract has a maturity date (expiry). After maturity, the PT rate and IBT rate are stored.
        • Flash Loans: The contract supports flash loans of IBTs.
    • YieldToken.sol: This contract allows users to hold and transfer tokens that represent their yield ownership. It integrates with a PT contract to track yield and ensure that yield is updated before any YT transfers. The contract is designed to work seamlessly with the PT contract, providing a comprehensive solution for managing yield and principal tokens.

      • Key Features

        • Yield Tracking: The YT contract keeps track of users' yield ownership by minting YT tokens in proportion to the PT tokens held by each user.
        • Integration with PT Contract: The YT contract interacts closely with the PT contract, allowing for seamless yield management. The PT contract updates the yield before any YT transfers, ensuring that users' yield ownership is always accurate.
        • Burn and Mint Functions: The YT contract provides functions for burning and minting YT tokens, which are only callable by the PT contract. This allows the PT contract to control the issuance and redemption of YT tokens.
        • Transfer and TransferFrom Functions: The YT contract overrides the standard ERC20 transfer and transferFrom functions to update the yield before any transfer. This ensures that users' yield ownership is maintained even after transfers.
      • Benefits of Using a YT Contract:

        • Efficient Yield Management: The YT contract provides an efficient way to track and manage yield ownership, reducing the need for complex calculations and manual processes.
        • Seamless Integration: The close integration with the PT contract ensures that yield is always up-to-date and that YT transfers are handled correctly.
        • Transparency and Auditability: The contract is transparent and auditable, providing users with confidence in the accuracy of their yield ownership.
        • Reduced Complexity: By abstracting away the complexities of yield management, the YT contract simplifies the process for users and developers.
  2. proxy

    • AMBeacon.sol: The AMBeacon contract, which is a modified version of the standard OpenZeppelin UpgradeableBeacon contract. It is used in conjunction with proxy contracts to determine their implementation contract.

      • Key Features:

        • Upgradeable: The beacon allows for the implementation contract to be upgraded, changing the logic of the proxy contracts that use it.
        • Access Control: Unlike the standard UpgradeableBeacon contract, which uses the Ownable pattern for access control, the AMBeacon contract uses the AccessManager contract from OpenZeppelin 5.0 for more granular access control.
        • Role-Based Access: Access to the upgradeTo function, which upgrades the beacon's implementation, is restricted to specific roles within the AccessManager contract.
      • Benefits of Using AMBeacon:

        • Improved Security: By using the AccessManager contract for access control, the AMBeacon contract provides more granular control over who can upgrade the beacon's implementation.
        • Flexibility: The role-based access control allows for different levels of access to the upgradeTo function, making it suitable for various governance models.
        • Reduced Complexity: The AMBeacon contract simplifies the process of upgrading proxy contracts by providing a central point of control for the implementation.
    • AMProxyAdmin.sol: The AMProxyAdmin contract, which is a modified version of the standard OpenZeppelin ProxyAdmin contract. It is used to manage the upgrades of transparent upgradeable proxies.

      • Key Features:

        • Proxy Management: The AMProxyAdmin contract allows for the upgrade of transparent upgradeable proxies to new implementation contracts.
        • Access Control: Unlike the standard ProxyAdmin contract, which uses the Ownable pattern for access control, the AMProxyAdmin contract uses the AccessManager contract from OpenZeppelin 5.0 for more granular access control.
        • Role-Based Access: Access to the upgradeAndCall function, which upgrades the proxy and calls a function on the new implementation, is restricted to specific roles within the AccessManager contract.
      • Benefits of Using AMProxyAdmin:

        • Improved Security: By using the AccessManager contract for access control, the AMProxyAdmin contract provides more granular control over who can upgrade proxies.
        • Flexibility: The role-based access control allows for different levels of access to the upgradeAndCall function, making it suitable for various governance models.
        • Reduced Complexity: The AMProxyAdmin contract simplifies the process of upgrading proxies by providing a central point of control.
    • AMTransparentUpgradeableProxy.sol: The AMTransparentUpgradeableProxy contract, which is a modified version of the standard OpenZeppelin TransparentUpgradeableProxy contract. It is used to create upgradeable transparent proxies that can be managed by a ProxyAdmin contract.

      • Key Features:

        • Upgradeable: The proxy can be upgraded to a new implementation contract, changing the logic of the proxy.
        • Transparent: The proxy forwards all calls to the implementation contract, making it appear as if the implementation contract is the actual contract being called.
        • Access Control: Unlike the standard TransparentUpgradeableProxy contract, which uses the Ownable pattern for access control, the AMTransparentUpgradeableProxy contract uses the AMProxyAdmin contract from the same codebase for more granular access control.
        • Role-Based Access: Access to the upgradeToAndCall function, which upgrades the proxy and calls a function on the new implementation, is restricted to specific roles within the AMProxyAdmin contract.
      • Benefits of Using AMTransparentUpgradeableProxy:

        • Improved Security: By using the AMProxyAdmin contract for access control, the AMTransparentUpgradeableProxy contract provides more granular control over who can upgrade the proxy.
        • Flexibility: The role-based access control allows for different levels of access to the upgradeToAndCall function, making it suitable for various governance models.
        • Reduced Complexity: The AMTransparentUpgradeableProxy contract simplifies the process of upgrading proxies by providing a central point of control.
  3. libraries

    • PrincipalTokenUtil.sol: The PrincipalTokenUtil, is a library that provides utility functions for working with principal tokens. Principal tokens are ERC-4626 tokens that represent a share of an underlying asset, such as a stablecoin or a basket of assets.

      • Key Features:

        • Conversion Functions: The library provides functions to convert between the underlying asset and principal token shares, taking into account the current exchange rate.
        • Yield Computation: The library provides a function to compute the yield accrued by a user since the last update, considering changes in the exchange rates of the principal token and the underlying asset.
        • Fee Computation: The library provides functions to compute the tokenization fee, yield fee, and flashloan fee for a given amount, based on the fee rates stored in a registry contract.
      • Functions:

        • _convertToSharesWithRate: Converts an amount of the underlying asset to an equivalent amount of principal token shares, using the specified exchange rate.
        • _convertToAssetsWithRate: Converts an amount of principal token shares to an equivalent amount of the underlying asset, using the specified exchange rate.
        • _computeYield: Computes the yield accrued by a user since the last update, considering changes in the exchange rates of the principal token and the underlying asset.
        • _tryGetTokenDecimals: Attempts to fetch the token decimals for a given token address.
        • _computeTokenizationFee: Computes the tokenization fee for a given amount, based on the fee rate stored in the registry contract.
        • _computeYieldFee: Computes the yield fee for a given amount, based on the fee rate stored in the registry contract.
        • _computeFlashloanFee: Computes the flashloan fee for a given amount, based on the fee rate stored in the registry contract.
      • Benefits of Using PrincipalTokenUtil:

        • Simplified Calculations: The library provides convenient functions for performing common calculations related to principal tokens, such as converting between assets and shares, computing yield, and calculating fees.
        • Accuracy and Precision: The library uses fixed-point arithmetic to ensure accurate and precise calculations, even for large amounts.
        • Extensibility: The library can be easily extended to support additional functionality or integrations with other contracts.
    • RayMath.sol: The RayMath, is a library that provides functions for converting between different decimal representations and a fixed-point representation called "Ray." Ray is a fixed-point representation with 27 decimal places, and it is commonly used in decentralized finance (DeFi) applications to represent values such as exchange rates and asset prices.

      • Key Features:

        • Decimal Conversions: The library provides functions to convert values from Ray to a specified number of decimal places, and vice versa.
        • Rounding Control: The fromRay function allows for specifying whether the conversion should be rounded up or down to the nearest integer.
        • Overflow Protection: The toRay function includes overflow protection to ensure that the conversion from a decimal representation to Ray does not result in an overflow.
      • Functions:

        • fromRay: Converts a value from Ray to a specified number of decimal places.
        • fromRay(uint256 _a, uint256 _decimals, bool _roundUp): Converts a value from Ray to a specified number of decimal places, with the option to round up or down.
        • toRay: Converts a value with a specified number of decimal places to Ray.
      • Benefits of Using RayMath:

        • Precision and Accuracy: Ray provides a fixed-point representation with high precision, making it suitable for representing values such as exchange rates and asset prices.
        • Interoperability: Ray is a commonly used representation in DeFi applications, making it easy to integrate with other contracts and protocols.
        • Overflow Protection: The toRay function includes overflow protection, ensuring that conversions from decimal representations to Ray do not result in overflows.

Chains supported

Ethereum Mainnet

Roles

  • Roles in the Spectra protocol:

    • Admin Role: Has the highest level of authority and can execute administrative functions such as pausing and unpausing the contract, changing the rewards proxy, and storing rates at expiry.
    • Pausable Role: Allows the account with this role to pause and unpause the contract.
    • Yield Claimer Role: Has permissions to update and claim yield.
    • Rewards Proxy Setter Role: Responsible for setting the rewards proxy contract address.
    • Flash Loan Role: Enables the contract to perform flash loans.
    • Beacon Authority: Responsible for managing the upgrade process by changing the implementation contract that the beacon points to.
    • Proxy Admin Role: Responsible for administering proxy contracts, specifically instances of TransparentUpgradeableProxy. The proxy admin has the authority to upgrade a proxy to a new implementation and optionally call a function on the new implementation.
    • Admin (AMTransparentUpgradeableProxy): Has the authority to upgrade the implementation of the proxy by calling the _dispatchUpgradeToAndCall function.
  1. PrincipalToken.sol: In PrincipalToken, there are several roles defined through the usage of access control modifiers provided by the AccessManagedUpgradeable contract. These roles include:

    • Admin Role: This role is typically assigned to the contract deployer or owner. It has the highest level of authority and can execute administrative functions such as pausing and unpausing the contract, changing the rewards proxy, and storing rates at expiry.

      ```solidity modifier restricted() { require(hasRole(ADMIN_ROLE, _msgSender()), "Restricted to admins"); _; } ```
    • Pausable Role: This role allows the account with this role to pause and unpause the contract.

      ```solidity /** @dev See {PausableUpgradeable-_pause}. */ function pause() external override restricted { _pause(); } /** @dev See {PausableUpgradeable-_unPause}. */ function unPause() external override restricted { _unpause(); } ```
    • Yield Claimer Role: This role has permissions to update and claim yield.

      ```solidity /** @dev See {IPrincipalToken-claimYield}. */ function claimYield(address _receiver) public override returns (uint256 yieldInAsset) { // ... } /** @dev See {IPrincipalToken-claimYieldInIBT}. */ function claimYieldInIBT(address _receiver) public override returns (uint256 yieldInIBT) { // ... } ```
    • Rewards Proxy Setter Role: This role is responsible for setting the rewards proxy contract address.

      ```solidity /** @dev See {IPrincipalToken-setRewardsProxy}. */ function setRewardsProxy(address _rewardsProxy) external restricted { // ... } ```
    • Flash Loan Role: This role enables the contract to perform flash loans.

      ```solidity /** * @dev See {IERC3156FlashLender-flashLoan}. */ function flashLoan( IERC3156FlashBorrower _receiver, address _token, uint256 _amount, bytes calldata _data ) external override returns (bool) { // ... } ```

      These roles are implemented using the hasRole function provided by OpenZeppelin's AccessControlUpgradeable contract and are enforced through the restricted modifier applied to various functions throughout the contract. Each of these roles grants specific permissions to perform certain actions within the contract, ensuring proper access control and security.

  2. AMBeacon.sol:

    1. Beacon Authority: This role is responsible for managing the upgrade process by changing the implementation contract that the beacon points to. The beacon authority can call the upgradeTo function to upgrade the beacon to a new implementation. By default, the restricted modifier ensures that only accounts with the appropriate role in the authority (typically the ADMIN_ROLE of the AccessManager contract) can perform upgrades. This role is assumed to be managed by an AccessManager contract.

    2. Implementation Contract: While not explicitly defined within this contract, the beacon points to an implementation contract whose address is stored in the _implementation variable. This contract is responsible for providing the logic that proxies will delegate function calls to. The beacon's upgradeTo function allows changing the implementation contract to a new one, effectively upgrading the logic of proxies that rely on this beacon.

    These two roles define the primary interactions and responsibilities within the contract.

  3. AMProxyAdmin.sol:

    1. Proxy Admin Role: This role is responsible for administering proxy contracts, specifically instances of TransparentUpgradeableProxy. The proxy admin has the authority to upgrade a proxy to a new implementation and optionally call a function on the new implementation. The proxy admin role is restricted to accounts that have the appropriate role in the access manager contract, which is enforced by the restricted modifier. The upgradeAndCall function allows upgrading the proxy and calling a function on the new implementation, if required. The access control for this function ensures that only authorized accounts can perform upgrades and calls on the proxy.

    This role is managed by an access manager contract, and only accounts with the necessary permissions (typically assigned to specific roles like ADMIN_ROLE) can perform proxy upgrades and function calls.

  4. AMTransparentUpgradeableProxy.sol: In AMTransparentUpgradeableProxy contract, the only role defined is that of the admin. The admin has the authority to upgrade the implementation of the proxy by calling the _dispatchUpgradeToAndCall function. Other than the admin, there are no specific roles defined within this contract.

Invariants Generated

  • IBT rate is only updated upon user interactions with our protocol

  • PT rate is only updated after an accounted negative rate change on the IBT rate

  • PT and its YT should have an equal supply at all times

  • PT rate should not increase

  • ptRateOfUser(u) β‰₯ ptRate for all u in users with users being all the users that deposited in the PT.

  • Accounted IBT rate cannot decrease without impacting PT rate

  • If the protocol records an IBT rate decrease, the PT rate has to decrease to account for the negative rate.

  • Principal Token is ERC5095

  • All EIP-5095 invariants should hold such as previewRedeem β‰₯ redeem.

  • Principal Token deposit

    • previewDeposit ≀ deposit : the preview of shares minted upon depositing should be less than or equal to the actual shares minted.

Approach Taken-in Evaluating Spectra Protocol

Accordingly, I analyzed and audited the subject in the following steps;

  1. Core Protocol Contract Overview:

    I focused on thoroughly understanding the codebase and providing recommendations to improve its functionality. The main goal was to take a close look at the important contracts and how they work together in the Spectra protocol.

    I start with the following contracts, which play crucial roles in the Spectra:

    Main Contracts I Looked At

    I start with the following contracts, which play crucial roles in the Spectra:

    PrincipalToken.sol YieldToken.sol AMBeacon.sol AMProxyAdmin.sol AMTransparentUpgradeableProxy.sol PrincipalTokenUtil.sol RayMath.sol

    I started my analysis by examining the intricate structure and functionalities of the Spectra protocol, which is a comprehensive suite of contracts that enables the creation and management of yield-bearing tokens. The protocol consists of three main components: tokens, proxy contracts, and libraries. The tokens include the PrincipalToken and YieldToken, which represent the principal and yield components of a yield-bearing asset, respectively. The proxy contracts include the AMBeacon, AMProxyAdmin, and AMTransparentUpgradeableProxy, which provide a flexible and secure mechanism for upgrading the implementation of the protocol's contracts. The libraries include the PrincipalTokenUtil and RayMath, which provide utility functions for working with principal tokens and fixed-point representations, respectively.

  2. Documentation Review:

    Then went to Review this docs for a more detailed and technical explanation of the Spectra.

  3. Compiling code and running provided tests:

  4. Manuel Code Review In this phase, I initially conducted a line-by-line analysis, following that, I engaged in a comparison mode.

    • Line by Line Analysis: Pay close attention to the contract's intended functionality and compare it with its actual behavior on a line-by-line basis.

    • Comparison Mode: Compare the implementation of each function with established standards or existing implementations, focusing on the function names to identify any deviations.

Codebase Quality

Overall, I consider the quality of the Spectra protocol codebase to be Good. The code appears to be mature and well-developed. We have noticed the implementation of various standards adhere to appropriately. Details are explained below:

Codebase Quality CategoriesComments
Architecture & DesignThe protocol features a modular design, segregating functionality into distinct contracts (e.g., proxy, token, libraries) for clarity and ease of maintenance. The use of libraries like RayMath for mathematical operations also indicates thoughtful design choices aimed at optimizing contract performance and gas efficiency.
Upgradeability & FlexibilityThe project does implement upgradeability patterns (e.g., proxy contracts), which might impact long-term maintainability. Considering an upgrade path or versioning strategy could enhance the project's flexibility in addressing future requirements..
Error Handling & Input ValidationFunctions check for conditions and validate inputs to prevent invalid operations, though the depth of validation (e.g., for edge cases transactions) would benefit from closer examination.
Security PracticesThe contracts demonstrate awareness of common security pitfalls in Solidity development. Functions are guarded with appropriate access control modifiers (e.g., onlyOwner, isAdmin checks), and state-changing functions are protected against reentrancy attacks. However, a comprehensive external security audit would be necessary to validate the absence of deeper vulnerabilities.
Code Maintainability and ReliabilityThe provided contracts are well-structured, exhibiting a solid foundation for maintainability and reliability. Each contract serves a specific purpose within the ecosystem, following established patterns and standards. This adherence to best practices and standards ensures that the code is not only secure but also future-proof. The usage of contracts for implementing token and security features like access control further underscores the commitment to code quality and reliability. However, the centralized control present in the form of admin and owner privileges could pose risks to decentralization and trust in the long term. Implementing decentralized governance or considering upgradeability through proxy contracts could mitigate these risks and enhance overall reliability.
Code CommentsThe contracts are accompanied by comprehensive comments, facilitating an understanding of the functional logic and critical operations within the code. Functions are described purposefully, and complex sections are elucidated with comments to guide readers through the logic. Despite this, certain areas, particularly those involving intricate mechanics or tokenomics, could benefit from even more detailed commentary to ensure clarity and ease of understanding for developers new to the project or those auditing the code.
TestingThe contracts exhibit a commendable level of test coverage, approaching nearly 100%, which is indicative of a robust testing regime. This coverage ensures that a wide array of functionalities and edge cases are tested, contributing to the reliability and security of the code. However, to further enhance the testing framework, the incorporation of fuzz testing and invariant testing is recommended. These testing methodologies can uncover deeper, systemic issues by simulating extreme conditions and verifying the invariants of the contract logic, thereby fortifying the codebase against unforeseen vulnerabilities.
Code Structure and FormattingThe codebase benefits from a consistent structure and formatting, adhering to the stylistic conventions and best practices of Solidity programming. Logical grouping of functions and adherence to naming conventions contribute significantly to the readability and navigability of the code. While the current structure supports clarity, further modularization and separation of concerns could be achieved by breaking down complex contracts into smaller, more focused components. This approach would not only simplify individual contract logic but also facilitate easier updates and maintenance.
StrengthsAmong the notable strengths of the codebase are its adherence to innovative integration of blockchain technology. The utilization of libraries for security and standard compliance emphasizes a commitment to code safety and interoperability. The creative use of PrincipalTokenUtil.sol and RayMath.sol in the yields mechanics demonstrates.
DocumentationThe contracts themselves contain comments and some descriptions of functionality, which aids in understanding the immediate logic. It was learned that the project also provides external documentation. However, it has been mentioned that this documentation is somewhat outdated. For a project of this complexity and scope, keeping the documentation up-to-date is crucial for developer onboarding, security audits, and community engagement. Addressing the discrepancies between the current codebase and the documentation will be essential for ensuring that all stakeholders have a clear and accurate understanding of the system's architecture and functionalities.

Architecturee

Principal Token

PrincipalToken

This is the core contract of Spectra. The Principal Token is EIP-5095 and EIP-2612 compliant. Users can deposit an EIP-4626 IBT or the underlying token of that IBT and receive Principal Tokens (PT) and Yield Tokens (YT). The PT contract holds the logic that separates the yield generated from the principal asset deposited in the IBT.

Yield Token

YieldToken

This contract represents the Yield Token (YT). The YT is an EIP-20 token and follows the EIP-2612 standard. The same amount of PT and YT is minted upon depositing into the protocol (PrincipalToken.deposit, PrincipalToken.depositIBT). The YT captures the yield generated by the deposited principal. Holding the YT allows the user to claim the corresponding amount of yield generated by the IBTs deposited in the associated PT contract.

Access Manager and Ownable

The Spectra protocol uses the OpenZeppelin AccessManager to manage the access control of the different protected functions.

We thus modified the Openzepellin Transparent Proxy, Beacon Proxy and Proxy Admin of OpenZeppelin to leverage the access manager instead of the Ownable pattern for the upgrade and admin functions.

File NameCore FunctionalityTechnical CharacteristicsImportance and Management
PrincipalToken.solThe PrincipalToken contract implements functionality for managing principal tokens, including depositing, withdrawing, redeeming, claiming fees and yields, and handling flash loans.It utilizes various interfaces and libraries such as ERC20PermitUpgradeable, AccessManagedUpgradeable, ReentrancyGuardUpgradeable, PausableUpgradeable, IERC4626, and IERC3156FlashBorrower.The contract's functionality is crucial for managing principal tokens, ensuring secure and efficient operations through modifiers like notExpired, afterExpiry, and internal functions for conversions and rate calculations. Additionally, it handles fee claiming, yield updates, and flash loans while managing various state variables and emitting relevant events.
YieldToken.solThe Yield Token (YT) contract tracks users' yield ownership, minted in sync with Principal Tokens (PT).It inherits from ERC20PermitUpgradeable, uses OpenZeppelin's Math library for arithmetic operations, and implements various functions for burning, minting, transferring, and checking balances.It ensures accurate tracking of yield ownership, integrates with the associated PT contract for updates, and manages transfers while enforcing certain conditions through modifier-based validations.
AMBeacon.solThe AMBeacon contract facilitates the determination of implementation contracts for BeaconProxy instances, allowing dynamic upgrading of their functionality.It inherits from AccessManaged for access control, utilizes the IBeacon interface, and emits events to signal implementation upgrades.It enables secure and flexible contract upgrades by allowing only authorized parties to change the implementation address, managed through the Access Manager contract.
AMProxyAdmin.solThe AMProxyAdmin contract serves as an admin for TransparentUpgradeableProxy instances, facilitating their upgrading and function invocation.It utilizes AccessManaged for access control, defines a version for the upgrade interface, and includes a function to upgrade and call a new implementation.This contract ensures secure and controlled upgrading of proxy contracts, with access managed through the Access Manager contract.
AMTransparentUpgradeableProxy.solThe AMTransparentUpgradeableProxy contract implements a transparent upgradeable proxy pattern, allowing for upgradability of contracts while maintaining transparency.It uses ERC1967Proxy as a base, employs a custom dispatch mechanism for upgrade and call functionality, and sets the admin during construction as an immutable variable.This contract ensures secure and transparent upgrades of proxy contracts, with administrative control managed by an instance of ProxyAdmin, facilitating seamless transitions to new implementations.
PrincipalTokenUtil.solThe PrincipalTokenUtil library provides functions for converting assets to shares and vice versa, computing user yield, and fetching token decimals.It uses math and rounding libraries for precise calculations, handles rate errors, and interacts with ERC20 token contracts to retrieve decimals.This library plays a crucial role in managing tokenization fees, yield fees, and flashloan fees, ensuring accurate calculations and efficient fee management in token-related operations.
RayMath.solThe RayMath library provides functions for converting values between Ray (27-decimal precision) and specified decimal precisions.It utilizes assembly code for efficient calculations, rounding options for precision control, and ensures integrity in value conversion.This library is essential for precise arithmetic operations involving different decimal precisions, ensuring accurate conversions and calculations in decentralized finance (DeFi) applications.

Systemic Risks, Centralization Risks, Technical Risks & Integration Risks

  1. PrincipalToken.sol

    1. Systemic Risks:

      • Flash Loan Vulnerabilities: The contract implements flash loan functionality, allowing users to borrow assets temporarily. Flash loan implementations can be susceptible to manipulation and abuse, leading to significant disruptions if exploited maliciously.

      • Price Oracle Dependency: The contract relies on external price oracles to determine exchange rates between assets. Inaccurate or manipulated price feeds can result in incorrect tokenization or redemption rates, leading to financial losses for users.

    2. Centralization Risks:

      • The contract has several functions that can only be accessed by a restricted set of addresses (restricted modifier). Depending on the implementation and management of these privileged addresses, there's a risk of centralization where control over critical functions is concentrated in a few entities.
    3. Technical Risks:

      • The contract implements flash loans (flashLoan function), which could introduce technical risks if not implemented securely. Flash loans are susceptible to various attacks such as reentrancy, front-running, and arbitrage if not properly handled.
    4. Integration Risks:

      • The contract integrates with external contracts (IERC4626, IRewardsProxy, IRegistry, IERC3156FlashBorrower, IERC3156FlashLender, IERC20) for various functionalities. Integration with external contracts introduces risks related to dependency on external systems, potential changes in interfaces, and unforeseen behavior of these external contracts.
  2. YieldToken.sol

    1. Systemic Risks:

      • Dependence on Time: The balanceOf function in the contract depends on the comparison of the current block timestamp with the maturity timestamp obtained from IPrincipalToken. Any discrepancy or manipulation of time-related variables could lead to systemic risks by affecting the calculation of token balances.

      • Interconnectedness: This contract interacts with other contracts in the system, such as IPrincipalToken. Changes or issues in these interconnected contracts could lead to systemic risks within the entire system.

    2. Centralization Risks:

      • Single Point of Failure: The contract has a single address pt which represents the associated principal token. If this token contract becomes compromised or inaccessible, it could impact the functionality of the YieldToken contract, potentially leading to centralization risks.
      • Control Over Minting and Burning: The YieldToken contract allows minting and burning functions to be called only by the principal token contract (pt). This centralizes control over these critical operations to the principal token contract.
    3. Technical Risks:

      • Reentrancy Vulnerability: Although not apparent in the provided code, if any of the functions in this contract or the contracts it interacts with allow external calls to untrusted contracts before updating state variables, it could potentially introduce reentrancy vulnerabilities.
    4. Integration Risks:

      • Compatibility Issues: The contract relies on external libraries and interfaces such as openzeppelin-math and openzeppelin-erc20-extensions. Changes or updates to these external dependencies could lead to integration risks if they are not compatible with the existing codebase.
      • Interface Consistency: The YieldToken contract implements various interfaces (IERC20, IYieldToken, ERC20Upgradeable). Any inconsistencies or mismatches between the implementations of these interfaces could lead to integration issues with other parts of the system.
  3. AMBeacon.sol

    1. Systemic Risks:

      • Upgrade Functionality: The upgradeTo function allows the authority to change the implementation contract address, affecting all proxies that rely on this beacon. If this upgrade process is not properly managed or if the new implementation has vulnerabilities, it could lead to systemic risks affecting all contracts using this beacon.

      • Access Control: The contract relies on access control provided by AccessManaged for managing authority roles. Any misconfiguration or unauthorized access to the upgrade functionality could lead to systemic risks, as it allows a single entity to control the upgrade process, potentially impacting the entire system.

      • Authority Control: The contract relies on a single authority, managed through AccessManaged, to determine the implementation contract address. This centralized control could lead to centralization risks if the authority misuses its power or if there's a single point of failure in managing upgrades.

      • Implementation Validation: The _setImplementation function checks if the provided newImplementation address points to a valid contract by verifying its bytecode length. However, this check may not be comprehensive enough to ensure the security and reliability of the new implementation. Additional checks or audits may be necessary to mitigate technical risks associated with using unverified or potentially malicious implementations.

      • Proxy Integration: Contracts that rely on this beacon must properly integrate with it to ensure seamless upgrades and compatibility with the new implementations. Any issues in integrating with the beacon or handling upgrades could lead to integration risks, potentially disrupting the functionality of contracts using this beacon.

  4. AMProxyAdmin.sol

    1. Systemic Risks:

      • Upgrade Functionality: The upgradeAndCall function allows for upgrading the proxy to a new implementation and calling a function on the new implementation. If not properly secured or if the new implementation has vulnerabilities, this could introduce systemic risks, especially if sensitive or critical functions are called during the upgrade process.
    2. Centralization Risks:

      • Single Authority: Similar to the previous contract, this contract relies on a single authority managed through AccessManaged for controlling upgrader roles. This centralized control could lead to centralization risks if the authority misuses its power or if there's a single point of failure in managing upgrades.
    3. Technical Risks:

      • Fallback Function Usage: The contract mentions the receive function, indicating the possibility of using it during an upgrade if the second argument of upgradeAndCall is an empty byte string. Depending on the implementation of the new contract, relying on the receive function during upgrades might introduce technical risks, especially if it's not handled correctly.
    4. Integration Risks:

      • Interface Versioning: The contract includes a versioning system for the upgrade interface (UPGRADE_INTERFACE_VERSION). Depending on the compatibility of this version with existing contracts and tools, integration risks may arise if there are changes in the interface version that are not backward compatible. Developers integrating this contract need to ensure compatibility with the specified version.
  5. AMTransparentUpgradeableProxy.sol

    1. Systemic Risks:

      • Upgrade Functionality: The upgradeToAndCall function enables upgrading the proxy to a new implementation and calling a function on the new implementation. If not properly secured or if the new implementation has vulnerabilities, this could introduce systemic risks, especially if sensitive or critical functions are called during the upgrade process.
    2. Centralization Risks:

      • Proxy Administration: The proxy's administration is handled by an instance of AMProxyAdmin, which is initially set during deployment and is immutable thereafter. This centralized control could lead to centralization risks if the admin account is compromised or misuses its power.
    3. Technical Risks:

      • Selector Clashes: The contract implements the transparent proxy pattern to avoid selector clashes, which can potentially be used in an attack. However, handling selector clashes requires careful management to ensure that there are no conflicts between existing and new functions. Any inadvertent conflicts could compromise the upgradeability and transparency of the proxy.
    4. Integration Risks:

      • ERC-1967 Compatibility: The contract implements ERC-1967 compatibility for upgradeable proxies. While this enhances interoperability, it also introduces integration risks if not properly understood or implemented. Developers integrating with this contract need to ensure they adhere to ERC-1967 standards to avoid unexpected behaviors or vulnerabilities.
  6. PrincipalTokenUtil.sol

    1. Systemic Risks:

      • Asset Decimals Handling: The _tryGetTokenDecimals function attempts to fetch token decimals from the given token address. If this operation fails or returns unexpected results, it could lead to systemic risks, especially if other parts of the system rely on accurate token decimals for calculations.
    2. Centralization Risks:

      • Registry Dependency: The contract relies on a registry contract (IRegistry) to fetch fee rates and other parameters. Centralization risks may arise if this registry contract is controlled by a single entity or has centralized governance, as changes to fee rates or other parameters could impact the entire system without sufficient decentralization.
    3. Technical Risks:

      • Rate Handling: Several functions (_computeYield, _convertToSharesWithRate, _convertToAssetsWithRate) involve rate calculations (e.g., PT rates, IBT rates). Incorrect rate handling could lead to technical risks such as miscalculations, underflows, or overflows, potentially resulting in financial losses or unexpected behavior.
    4. Integration Risks:

      • External Contracts Interaction: The contract interacts with external contracts such as yield tokens, principal tokens, and registries. Integration risks may arise if these external contracts change their interfaces, behavior, or implementation details, potentially causing the current contract to malfunction or behave unexpectedly. Solidity version upgrades or changes to OpenZeppelin interfaces could also introduce integration risks.
  7. RayMath.sol

    1. Systemic Risks:

      • Precision Loss: The fromRay function converts a value from Ray (27-decimal precision) to a representation with a specified number of decimals. Precision loss can occur during this conversion, especially if the target decimals are significantly lower than 27, leading to potential systemic risks in financial calculations.
    2. Centralization Risks:

      • Single Authorship: The RayMath library is authored by a single entity ("Spectra"). Centralization risks may arise if maintenance or updates to this library are solely dependent on this single entity, potentially leading to bottlenecks or vulnerabilities if the entity becomes unavailable or unresponsive.
    3. Technical Risks:

      • Assembly Usage: The library extensively uses inline assembly for arithmetic operations. While assembly can be more efficient, it introduces technical risks due to potential vulnerabilities or errors in assembly code, such as integer overflows, underflows, or incorrect logic, which could compromise the integrity and security of the library.
      • Rounding Mechanism: The fromRay function includes a rounding mechanism based on the _roundUp parameter. Incorrect rounding or edge cases not handled properly could lead to technical risks such as incorrect rounding behavior or unexpected results in financial calculations.
    4. Integration Risks:

      • Dependency on External Contracts: If other contracts within the system rely on the RayMath library for decimal conversions, any changes or updates to this library could potentially introduce integration risks. Changes in function signatures, logic, or behavior of the RayMath library may require corresponding updates in dependent contracts to ensure compatibility and proper functioning.

Suggestions

What could they have done better?

    1. If we look at the test scope and content of the project with a systematic checklist, we can see which parts are good and which areas have room for improvement As a result of my analysis, those marked in green are the ones that the project has fully achieved. The remaining areas are the development areas of the project in terms of testing ;

test-cases.jpg

    1. It is recommended to increase the test coverage to 100% so make sure that each and every line is battle tested

Suggestions for the Spectra Protocol

  1. Dynamic Fee Structures: Implement dynamic fee structures that adjust based on market conditions, user activity, or other relevant factors. This flexibility can optimize revenue generation while ensuring competitive fees for users, ultimately enhancing protocol sustainability.

  2. Liquidity Incentives: Introduce liquidity mining programs or yield farming incentives to attract liquidity providers and boost trading activity within the protocol. Rewarding users with tokens or other incentives can stimulate participation and foster a vibrant ecosystem.

  3. Cross-Protocol Integrations: Explore opportunities for integrating with other DeFi protocols, such as decentralized exchanges (DEXs), lending platforms, or asset management protocols. Cross-protocol integrations can unlock new use cases, enhance liquidity, and create synergies between different DeFi ecosystems.

  4. Risk Management Tools: Provide users with comprehensive risk management tools and analytics to assess and mitigate risks associated with yield farming, liquidity provision, and other activities. Empowering users with data-driven insights can help them make informed decisions and navigate volatile market conditions more effectively.

  5. Community Governance: Transition towards a decentralized governance model where protocol decisions are made collectively by the community through governance tokens and voting mechanisms. Community governance fosters decentralization, transparency, and inclusivity, aligning the protocol's interests with those of its stakeholders.

  6. Staking and Voting Rewards: Incentivize token holders to actively participate in governance and decision-making processes by offering staking rewards and voting incentives. Rewarding users for their engagement encourages active participation and strengthens the protocol's governance mechanisms.

  7. Audits and Security Enhancements: Conduct regular security audits and implement robust security measures to protect user funds and safeguard the integrity of the protocol. Prioritize code reviews, bug bounties, and continuous monitoring to proactively identify and address potential vulnerabilities.

What’s unique?

  1. Yield-Bearing Tokens: Spectra introduces the concept of yield-bearing tokens (YT), which represent ownership of the yield generated by principal tokens (PT) deposited in the protocol. This innovative mechanism allows users to earn passive income from their deposited assets, enhancing the utility of their holdings.

  2. Modular Architecture: The protocol's modular architecture enables seamless integration of new features and upgrades without disrupting existing functionality. By leveraging proxy contracts and libraries, Spectra ensures flexibility, extensibility, and maintainability, allowing for efficient protocol evolution over time.

  3. Flash Loan Support: Spectra supports flash loans, allowing users to borrow assets temporarily without collateralization. This feature facilitates efficient capital deployment and arbitrage opportunities, enhancing liquidity and trading activity within the protocol.

  4. Fee Customization: The protocol offers customizable fee structures for tokenization, yield claiming, and flash loans, empowering administrators to adjust fees based on market conditions and protocol requirements. This flexibility ensures sustainable revenue generation while maintaining competitiveness and user satisfaction.

  5. Secure Mathematical Operations: Spectra incorporates the RayMath library for precise mathematical operations and conversions, ensuring accuracy and reliability in complex financial calculations. By using fixed-point arithmetic and overflow protection, the protocol minimizes errors and vulnerabilities, enhancing security and trustworthiness.

Issues surfaced from Attack Ideas in README

  • Decimals imprecisions should always benefit the protocol and no user should be able to extract extra value.

  • Proxy Admin and Beacon are a modified version of Openzepelin origin contract replacin OZ Ownable with OZ Access Managed. Check if this modification can be harmful outside of our trust model.

  • Imprecisions and rounding errors.

  • Manipulation of the IBT rate.

  • Mechanism of negative rates and the impact on the PT rate.

Time spent:

30 hours

#0 - c4-pre-sort

2024-03-03T14:04:56Z

gzeon-c4 marked the issue as high quality report

#1 - c4-pre-sort

2024-03-03T14:51:25Z

gzeon-c4 marked the issue as sufficient quality report

#2 - jeanchambras

2024-03-09T19:05:49Z

The report is of great quality. I noticed some confusion regarding the roles within the protocol. The risk assessment, although simplistic and possibly reused in part from past audits, is well-curated within the context of this audit.

#3 - c4-judge

2024-03-11T00:50:20Z

JustDravee marked the issue as grade-a

#4 - c4-judge

2024-03-11T01:58:34Z

JustDravee marked the issue as selected for report

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax Β© 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter