Assessment reports>Avantis>Threat Model>unlock

Function: unlock(uint256 tokenId)

This unlocks a specific tokenId.

Inputs

  • tokenId

    • Control: Fully controlled by the caller.

    • Constraints: The owner of tokenId should be msg.sender.

    • Impact: The ID of the token to unlock.

Branches and code coverage

Intended branches

  • The number of tokens to unlock for the provided tokenId should be greater than zero.

  • The owner of tokenId should be msg.sender.

  • The fee returned by checkUnlockFee should be sent to the vault manager.

  • The remaining amount should be transferred to msg.sender, and the tokenId should be burned.

  • Updates the rewards for the caller and transfers the reward amount.

  • Deletes the mappings for the tokenId.

Negative behavior

  • Revert if the caller is not msg.sender.

  • Revert if the number of tokens to unlock for the provided tokenId is zero.

Function call analysis

  • this.checkUnlockFee(tokenId) -> this.getEarlyWithdrawFee(this.tokensByTokenId[tokenId]) -> this.tranche.feesOn()

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? Returns true if fees are on, otherwise false; return value is not in control of the user.

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

  • this.checkUnlockFee(tokenId) -> this.getEarlyWithdrawFee(this.tokensByTokenId[tokenId]) -> this.vaultManager.earlyWithdrawFee()

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? Returns the early withdrawal fees; return value is not in control of the user.

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

  • this.checkUnlockFee(tokenId) -> MathUpgradeable.mulDiv(fee, timeLeft, totalTime, Rounding.Up)

    • What is controllable? fee, timeLeft, and totalTime.

    • If the return value is controllable, how is it used and how can it go wrong? The fee calculation is based on these parameters; incorrect values may lead to incorrect fee calculation.

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

  • this._claimRewards(tokenId) -> SafeERC20.safeTransfer(IERC20(this.tranche.asset()), this._ownerOf(tokenId), this.rewardsByTokenId[tokenId])

    • What is controllable? this._ownerOf(tokenId) and this.rewardsByTokenId[tokenId].

    • If the return value is controllable, how is it used and how can it go wrong? The reward amount is transferred to the owner of the token; an incorrect owner will be reverted in the previous check.

    • What happens if it reverts, reenters, or does other unusual control flow? If it reverts, the entire call will revert — no reentrancy scenarios.

  • this._claimRewards(tokenId) -> this.tranche.asset()

    • What is controllable? N/A.

    • 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? N/A.

  • this.tranche.transfer(msg.sender, this.tokensByTokenId[tokenId] - fee)

    • What is controllable? msg.sender and this.tokensByTokenId[tokenId] - fee.

    • If the return value is controllable, how is it used and how can it go wrong? The remaining unlocked tokens are transferred to the caller; incorrect values may lead to incorrect token transfer.

    • What happens if it reverts, reenters, or does other unusual control flow? If it reverts, the entire call will revert — no reentrancy scenarios.

  • this.tranche.transfer(address(this.vaultManager), fee)

    • What is controllable? fee.

    • If the return value is controllable, how is it used and how can it go wrong? The fee amount is transferred to the vault manager; an incorrect fee may lead to incorrect fee transfer.

    • What happens if it reverts, reenters, or does other unusual control flow? If it reverts, the entire call will revert — no reentrancy scenarios.

Zellic © 2025Back to top ↑