Assessment reports>Origami Finance>Threat Model>exitToToken

Function: exitToToken(address, IOrigamiInvestment.ExitQuoteData quoteData, address recipient)

The function can be called only from the lovToken contract. Allows investor to exit from the reserve token.

Inputs

  • quoteData.investmentTokenAmount

    • Constraints: Is not validated here — all checks performed by the lovToken contract.

    • Impact: lovTokens will be burned from the manager account.

  • quoteData.toToken

    • Constraints: There is verification that toToken can be equal to the depositAsset or _reserveToken; otherwise, the transaction will revert.

    • Impact: The recipient will receive these tokens in return — toToken should be an accepted ERC-20 token.

  • quoteData.maxSlippageBps

    • Constraints: Is not used and is not validated.

    • Impact: The maximum allowed slippage of the expectedToTokenAmount.

  • quoteData.deadline

    • Constraints: Is not used and is not validated.

    • Impact: N/A.

  • quoteData.expectedToTokenAmount

    • Constraints: Is not used and is not validated.

    • Impact: N/A.

  • quoteData.minToTokenAmount

    • Constraints: There is a check that toTokenAmount is not less than quoteData.minToTokenAmount.

    • Impact: The minimum amount of toToken to receive.

  • quoteData.underlyingInvestmentQuoteData

    • Constraints: Is not used and is not validated.

    • Impact: N/A.

  • recipient

    • Constraints: Cannot be zero address.

    • Impact: The receiver of the toToken.

Branches and code coverage

Intended branches

  • exitToToken was successfully completed as expected.

Negative behavior

  • Caller is not an approved lovToken contract.

  • The toTokenAmount is less than minToTokenAmount.

  • toToken is not supported.

  • recipient is zero address.

  • The pause state for exit is true

Function call analysis

  • this.populateCache() -> this.liabilities() -> this.lendingClerk.borrowerDebt(address(this))

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? The value is used to calculate the debt converted to shares, which in turn is used for A/L ratio calculation.

    • What happens if it reverts, reenters or does other unusual control flow? The function returns the current debt of this manager contract. The balance of debt tokens can be changed only over borrow/repay function or by the minter of debt tokens, who can transfer debt tokens between accounts.

  • this.populateCache() -> this.liabilities() -> this._reserveToken.previewWithdraw(debtInDepositAsset)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? Returns debt amount converted to the shares. The value is used for cache.liabilities.

    • What happens if it reverts, reenters or does other unusual control flow? N/A.

  • this.populateCache() -> this.lovToken.totalSupply()

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? Returns full number of minted lovTokens. The value is used for cache.totalSupply.

    • What happens if it reverts, reenters or does other unusual control flow? N/A.

  • this._assetToLiabilityRatio(cache) -> OrigamiMath.mulDiv(cache.assets, OrigamiAbstractLovTokenManager.PRECISION, cache.liabilities, Rounding.ROUND_DOWN)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? Returns current L/A ratio, which is calculated using total reserves balance cache.assets, which is equal to reservesBalance(), and debt shares, which is equal to the cache.liabilities.

    • What happens if it reverts, reenters or does other unusual control flow? N/A.

  • BasisPointFraction.getRemainder(this.exitFeeRate, toBurnAmount)

    • What is controllable? toBurnAmount.

    • If the return value is controllable, how is it used and how can it go wrong? Returns the number of tokens minus the exit fee.

    • What happens if it reverts, reenters or does other unusual control flow? Can revert if exitFeeRate is more than BASIS_POINTS_DIVISOR.

  • this._sharesToReserves(cache, reservesAmount) -> OrigamiMath.mulDiv(shares, this._userRedeemableReserves(cache), cache.totalSupply, Rounding.ROUND_DOWN)

    • What is controllable? reservesAmount == shares.

    • If the return value is controllable, how is it used and how can it go wrong? N/A.

    • What happens if it reverts, reenters or does other unusual control flow? In case cache.totalSupply is not zero, the reserved amount will be calculated as follows: shares.mulDiv(_userRedeemableReserves(cache), cache.totalSupply, OrigamiMath.Rounding.ROUND_DOWN);.

  • this._sharesToReserves(cache, reservesAmount) -> this._userRedeemableReserves(cache)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? Can return zero; if redeemable reserves are not available (cache.assets is less than liabilities with buffer), then the _sharesToReserves function result also will be equal to zero.

    • What happens if it reverts, reenters or does other unusual control flow? N/A.

  • this._redeemFromReserves(reservesAmount, quoteData.toToken, recipient) -> OrigamiLovTokenErc4626Manager._redeemFromReserves

    • What is controllable? quoteData.toToken and recipient.

    • If the return value is controllable, how is it used and how can it go wrong? Returns the amount of redeemed tokens.

    • What happens if it reverts, reenters or does other unusual control flow? The function will revert if toToken is neither depositAsset or _reserveToken. If equal to _reserveToken, reservesAmount of _reserveToken will be transferred to the recipient. Otherwise, the reservesAmount amount of tokens will be redeemed from the _reserveToken contract, the reservesAmount reserve tokens will be burned, and assets tokens will transferred to the recipient.

Zellic © 2025Back to top ↑