Skip to main content

Yeti Finance Contracts

Smart Contract Security Assessment

May 13, 2022

Yeti

SUMMARY


ABSTRACT

Dedaub was commissioned to perform an audit on selected contracts from Yeti Finance’s 0xmebius/vault repository. In the past, we have audited other parts of the Yeti protocol (although not yet its entirety) and such past reports should be consulted jointly with the current.

The essence of the audited functionality is primarily the addition of UST/aUST as collateral for the Yeti protocol. (Secondarily, the audited code includes the integration of Platypus Swap.)

The audited contracts list is the following:

0xmebius/vault

** ** Commit db2c5c852c5c63a94059068fac6fbc26a2245330

contracts/src/Router.sol contracts/src/SwapFacility.sol contracts/src/integrations/aUSTVault.sol contracts/src/integrations/aUSTVaultV2.sol contracts/src/integrations/savaxVault.sol

Two auditors worked on the codebase over one week.


SETTING & CAVEATS

Recent developments have made UST virtually worthless, so this functionality is very unlikely to be deployed as-is. However, the audit’s focus is not the specifics of UST but the general pattern, implemented in two different ways in aUSTVault and aUSTVaultV2, of accepting collateral whose staking will be finalized asynchronously. In the case of UST/aUST, depositing UST results in the minting of aUST (which is the real holding token that the Yeti Vault wants to keep long term) at a future block. The accounting of deposits/redeems/stakes for such asynchronous transactions is the main audited functionality.

In the case of the aUSTVault, the implementation works as follows:

  • the client deposits UST
  • the vault requests its conversion to aUST, to happen asynchronously
  • the underlying token for protocol purposes is UST
    • implying that protocol fees are paid in UST
  • the token the client receives upon redemption is UST
  • for the client to receive UST, a swap is performed. A SwapFacility contract needs to maintain its own UST budget, to act as a buffer.

In the case of the aUSTVaultV2, the implementation works as follows:

  • the client deposits UST
  • the vault requests its conversion to aUST, to happen asynchronously
  • the underlying token for protocol purposes is aUST
    • implying that protocol fees are paid in aUST
  • the token the client receives upon redemption is aUST. This requires redefining the standard Vault functionality, which assumes that the client receives the underlying token.

The audit’s main target is security threats, i.e., what the community understanding would likely call "hacking", rather than regular use of the protocol. Functional correctness (i.e., issues in "regular use") is a secondary consideration. Typically it can only be covered if we are provided with unambiguous (i.e., full-detail) specifications of what is the expected, correct behavior. In terms of functional correctness, we often trusted the code’s calculations and interactions, in the absence of any other specification. Functional correctness relative to low-level calculations (including units, scaling, quantities returned from external protocols) is generally most effectively done through thorough testing rather than human auditing.


PROTOCOL-LEVEL CONSIDERATIONS

The main protocol-level consideration is inherent and one that the development team may be already aware of: the asynchrony in the receipt of the holding token (aUST) can create accounting irregularities. In the case of aUSTVaultV2:

  • a call to compound right after the first deposit will try to transfer aUST to the fee collection contracts, which will fail unless the contract has an aUST balance before its first transaction;
  • the amount accounted for, based on a Chainlink oracle price, may be smaller than the amount of aUST that will be received at a future block, upon wrapping the supplied UST.

The second element can create broader issues, e.g.,:

  • there may not be enough aUST to satisfy redeem requests
  • the first redeemers may receive more aUST, based on the inflated accounting
  • the contract will be misleading its users by reporting a higher underlyingPerReceipt.

Similar issues arise for aUSTVault (but perhaps to a lesser extent). The client is being issued Vault tokens based on an exchange rate r1, yet the aUST holdings of the contract may reflect a later rate r2.

For these issues to be surmountable, operation of the contracts needs to be monitored, so that the deviation of prices due to the asynchrony can stay within bounds. The contracts already export the forceBalanceUpdate functionality for bringing the balances to sync.


VULNERABILITIES & FUNCTIONAL ISSUES

This section details issues that affect the functionality of the contract. Dedaub generally categorizes issues according to the following severities, but may also take other considerations into account such as impact or difficulty in exploitation:

Category
Description
CRITICAL
Can be profitably exploited by any knowledgeable third-party attacker to drain a portion of the system’s or users’ funds OR the contract does not function as intended and severe loss of funds may result.
HIGH
Third-party attackers or faulty functionality may block the system or cause the system or users to lose funds. Important system invariants can be violated.
MEDIUM
Examples:
  • User or system funds can be lost when third-party systems misbehave.
  • DoS, under specific conditions.
  • Part of the functionality becomes unusable due to a programming error.
LOW
Examples:
  • Breaking important system invariants but without apparent consequences.
  • Buggy functionality for trusted users where a workaround exists.
  • Security issues which may manifest when the system evolves.

Issue resolution includes “dismissed”, by the client, or “resolved”, per the auditors.


CRITICAL SEVERITY

[No critical severity issues]


HIGH SEVERITY

[No high severity issues]


MEDIUM SEVERITY

[No medium severity issues]


LOW SEVERITY

[No low severity issues]


OTHER/ADVISORY ISSUES

This section details issues that are not thought to directly affect the functionality of the project, but we recommend considering them.

A1

Several opportunities for gas savings by avoiding unnecessary storage operations (loads/stores)

A1ADVISORY

Several opportunities for gas savings by avoiding unnecessary storage operations (loads/stores)
open

The code can benefit from easy and impactful gas optimization without changing accessibility, via a load/store model. This is less important on Avalanche, but gas optimization for repeat operations is likely to remain an issue, and the cost of storage reads/writes is large. We highlight a few instances. They can be optimized by loading the values from storage to local variables at the beginning and updating them at the end, with intermediate operations over local variables.

In aUSTVault:

function _triggerDepositAction(uint256 amtOfUnderlying) internal override {
lastaUSTBalance = aUST.balanceOf(address(this)); // Dedaub: SSTORE
lastUSTBalance = max(lastUSTBalance, _getUSTaUST() *
lastaUSTBalance / 1e18); // Dedaub: 2 SLOAD, 1 SSTORE
lastUSTBalance += amtOfUnderlying; // Dedaub: 1 SLOAD, 1 SSTORE
xAnchor.depositStable(address(underlying), amtOfUnderlying);
}
function _triggerWithdrawAction(uint256 amtToReturn) internal override {
swapper.swapAmountOut(amtToReturn);
lastaUSTBalance = aUST.balanceOf(address(this)); // Dedaub: SSTORE
lastUSTBalance -= amtToReturn; // Dedaub: 1 SLOAD, 1 SSTORE
lastUSTBalance = max(lastUSTBalance, _getUSTaUST() *
lastaUSTBalance / 1e18); // Dedaub: 2 SLOAD, 1 SSTORE
}

In aUSTVaultV2:

function _compound() internal returns (uint256) {

lastaUSTBalance = getTrueUnderlyingBalance(); // Dedaub: SSTORE
lastUSTBalance = _getUSTaUST() * lastaUSTBalance / 1e18;
// Dedaub: SLOAD of previous SSTORE
}

A2

Misleading comments in savaxVault

A2ADVISORY

Misleading comments in savaxVault
open

Comments in the savaxVault contract refer to compVault and compToken, not to the savaxVault.

A3

Misleading comment in aUSTVaultV2

A3ADVISORY

Misleading comment in aUSTVaultV2
open

The underlying asset of aUSTVaultV2 is aUST and not UST. This is not reflected correctly in the comment below.

address _underlying, // UST

Similarly, the comment in deposit refers to depositing underlying, which is not the case in this contract.

A4

Comments in Router need to be updated

A4ADVISORY

Comments in Router need to be updated
open

Comments in the Router contract related to the Node struct need to be updated to reflect the new routes for Yeti Vault Token and Platypus Pool.

A5

Redundant ISwapFacility state variable in aUSTVault2

A5ADVISORY

Redundant ISwapFacility state variable in aUSTVault2
open

The contract aUSTVault2 imports ISwapFacility and declares an ISwapFacility state variable, when in reality it does not use it.

A6

State variable targets implementation instead of interface in aUSTVault2

A6ADVISORY

State variable targets implementation instead of interface in aUSTVault2
open

In the contract aUSTVault2, the state variable UST is of type ERC20 instead of IERC20.

A7

Compiler bugs

A7ADVISORY

Compiler bugs
info

The contracts are compiled with the Solidity compiler v0.8.10 which, at the time of writing, has no known issues.



DISCLAIMER

The audited contracts have been analyzed using automated techniques and extensive human inspection in accordance with state-of-the-art practices as of the date of this report. The audit makes no statements or warranties on the security of the code. On its own, it cannot be considered a sufficient assessment of the correctness of the contract. While we have conducted an analysis to the best of our ability, it is our recommendation for high-value contracts to commission several independent audits, a public bug bounty program, as well as continuous security auditing and monitoring through Dedaub Security Suite.


ABOUT DEDAUB

Dedaub offers significant security expertise combined with cutting-edge program analysis technology to secure some of the most prominent protocols in DeFi. The founders, as well as many of Dedaub's auditors, have a strong academic research background together with a real-world hacker mentality to secure code. Protocol blockchain developers hire us for our foundational analysis tools and deep expertise in program analysis, reverse engineering, DeFi exploits, cryptography and financial mathematics.