Superform Protocol

repository·main·Indexed 41 days ago

https://github.com/superform-xyz/superform-core

A modular, non-custodial yield routing and distribution platform that enables intent-based transactions across ERC4626 vaults, multiple chains, and assets. The protocol features a Core and Periphery architecture, utilizing State Registries and Arbitrary Message Bridges (AMBs) to facilitate cross-chain deposits and withdrawals via SuperPositions.

Tokens
42.6K
Snippets
95
Records
191
Agent score
100%

What's inside Superform

  1. Overview of Superform Protocol

    main

    Superform Protocol is a suite of non-upgradeable, non-custodial smart contracts that serves as a central repository for yield and a router for users. It is modular and permissionless, allowing for intent-based transactions across multiple tokens, chains, and vaults in a single transaction.

    For DeFi Protocols

    • Permissionless Listing: Add ERC4626-compliant vaults to the protocol by adding them to a 'Form' (a vault adapter).
    • Protocol Presence: Create profile pages with embeddable data sources.
    • Metadata Management: Manage metadata for yield opportunities.
    • Cross-chain Access: Users can deposit into your vaults from any chain without needing to deploy your vaults on that chain.

    For Users

    • Unified Access: Deposit or withdraw into any vault using any asset from any chain.
    • Batching: Execute multiple actions across multiple vaults and chains in one transaction.
    • Portfolio Management: Automate yield portfolios and automatic compounding.
    • Cross-chain Execution: Use multiple AMBs (Asynchronous Messaging Bridges) for cross-chain transactions.
  2. Understand fee estimation risks in PaymentHelper

    main

    When using PaymentHelper to estimate fees for router operations, be aware of two potential discrepancies that may lead to incorrect payment amounts:

    1. Overpayment on Same-Chain Operations: The estimation functions (like estimateMultiDstSingleVault and estimateMultiDstMultiVault) may assume all requests are cross-chain. If a request includes same-chain (direct) operations, they do not require update, acknowledgement (ack), processing, or swap costs. Relying on these estimates for mixed same-chain/cross-chain requests may result in overpaying fees.

    2. Underpayment on Withdrawals: The estimation functions mistakenly skip calculating the acknowledgement (ack) processing cost when isDeposit_ is set to false. For cross-chain withdrawals, the acknowledgement process (where the destination chain notifies the source chain of success or failure) incurs a cost. If you are estimating fees for a withdrawal, ensure you account for _estimateAckProcessingCost to avoid underestimating the required payment.

  3. Cross-chain message quorum requirements

    main

    Superform uses an AMB (Asynchronous Messaging Bridge) system for cross-chain operations. When dispatching messages via _dispatchAmbMessage, the system checks if the number of provided AMB IDs meets the destination chain's quorum requirement using _getQuorum(dstChainId_).

    Warning: There is a known risk where the system may validate the message quorum on the destination chain using the source chain's quorum value (_getQuorum(srcChainId)). If the destination chain requires a higher quorum than the source chain, messages may fail to process and become stuck. When designing cross-chain flows, ensure the number of AMBs provided satisfies the requirements of both the source and destination chains.

  4. Security assumptions of the State Registry

    main

    When interacting with or building upon the State Registry, note the following security constraints:

    • Write Access: Only approved AMB implementation contracts are permitted to write new messages into the state registry.
    • Authentication: Senders must be authenticated to interact with the AMB implementation contracts.
    • Privileged Roles: Updating and processing payloads is restricted to keepers with special privileges.
    • Modifier Overrides: The onlySender modifier is overridden by all contracts that inherit from the BaseStateRegistry to allow for the necessary cross-chain permission model.
  5. Understand PayMaster ERC20 handling and dust sweeping

    main

    The PayMaster contract is not limited to managing native token transfers; it can also handle ERC20 tokens.

    Dust Sweeping: The function _processForwardDustToPaymaster() (called via _forwardDustToPaymaster()) identifies the vault's asset using getVaultAsset() and sweeps any remaining balance (dust) to the PAYMASTER address registered in the superRegistry.

    Withdrawals: While withdrawTo allows the onlyPaymentAdmin to withdraw native tokens from the PayMaster, users should be aware that the current implementation lacks a dedicated withdrawERC20 function, even though the PayMaster can accumulate ERC20 tokens via the dust sweeping mechanism.

    function _processForwardDustToPaymaster() internal {
        address paymaster = superRegistry.getAddress(keccak256("PAYMASTER"));
        IERC20 token = IERC20(getVaultAsset());
    
        uint256 dust = token.balanceOf(address(this));
        if (dust != 0) {
            token.safeTransfer(paymaster, dust);
        }
    }
  6. Note on Cross-Chain Adapter RetryPayload implementations

    main

    When working with cross-chain adapters (Wormhole, LayerZero, Hyperlane), be aware that while the retryPayload function name is shared across these implementations, their underlying logic and behaviors differ significantly:

    • Wormhole AMB: The retryPayload function resends the same payload from the source chain to the destination chain.
    • LayerZero AMB: The retryPayload function retries a failed payload on the destination chain by calling lzReceive using the payload stored in the LayerZero endpoint.
  7. Understand Superform Router direct deposit receiver behavior

    main

    When performing direct deposits via the SuperformRouter using singleDirectSingleVaultDeposit or singleDirectMultiVaultDeposit with retain4626 set to false, be aware of how SuperPositions are minted.

    Currently, the implementation mints SuperPositions to the srcSender_ (the caller) instead of the vaultData_.receiverAddress specified in the request. This may break assumptions if you intend for the positions to be sent to a different address than the one initiating the transaction.

    // In BaseRouterImplementation.sol
    // Current behavior: mints to srcSender_ instead of vaultData_.receiverAddress
    ISuperPositions(superRegistry.getAddress(keccak256("SUPER_POSITIONS"))).mintSingle(
        srcSender_, 
        vaultData_.superformId, 
        dstAmount
    );
  8. Withdraw excess ETH or tokens from contracts

    main

    Contracts like BaseForm, BaseRouter, and DstSwapper include a receive() external payable {} function, allowing users to accidentally send ETH or other ERC20 assets to them. Currently, these contracts lack a mechanism to withdraw these unclaimed or accidental funds.

    Recommendation: Implement a withdrawTo style function (similar to the one in the PayMaster contract) that allows an administrator to withdraw excess ETH and ERC20 tokens. The implementation must ensure that only excess funds are withdrawn and not active user assets.

  9. Security considerations for Upgradable Vaults in Superforms

    main

    Because Superform connects users to underlying ERC4626 vaults, there is a risk that a vault administrator could update a vault's implementation to harm users (e.g., redirecting deposits to an attacker).

    When building or using Superforms with upgradable vaults, consider the following security patterns:

    • Proxy Detection: Identify if the underlying vault is a proxy.
    • Pause Functionality: The ability to pause individual superforms if a proxy change is detected.
    • Implementation Checks: Using adapters to verify that the underlying vault implementation has not changed before allowing deposits or withdrawals.
  10. Manage bridge addresses in SuperRegistry

    main

    The setBridgeAddresses function in the SuperRegistry contract allows admins to add new bridge addresses and validators. However, current implementation lacks the ability to update, remove, or pause existing bridge addresses.

    This creates risks if:

    1. A bridge or validator becomes buggy or compromised.
    2. A bridge (like li.fi) undergoes an upgrade that changes its txData structure, making existing validator contracts incompatible.

    Recommendation: Modify setBridgeAddresses to allow protocol admins to update or pause existing bridge addresses and their validators.

  11. Avoid overpaying for transaction costs in PaymentHelper

    main
    The PaymentHelper contract (e.g., via estimateMultiDstMultiVault) is used to estimate transaction costs so users can provide sufficient funds. However, these estimates may include 'ack costs' (acknowledgment costs) even when the user does not intend to mint SuperPosition tokens on the destination chain. If a user retains deposited shares on the destination chain instead of minting tokens, no acknowledgment needs to be sent back to the source chain. To avoid overpaying, ensure that acknowledgment costs are only calculated when SuperPosition minting is actually required.
  12. Use immutable for expressions like keccak256()

    main

    When defining variables that are calculated via expressions (such as keccak256() calls) rather than literal values, use the immutable keyword instead of constant. While constant is for literal values written directly into the code, immutable is appropriate for values calculated during deployment or passed into the constructor.

    // Use immutable for expressions
    bytes32 public immutable SOME_HASH = keccak256("SOME_VALUE");
    
    // Use constant for literals
    bytes32 public constant SOME_LITERAL = 0x1234...