CryptoReal
CASE FILE — Mar 28, 2022

Reentrancy Bug in Revest's NFT Vaults Drains $2M Across Three Protocols

Revest Finance, a platform that describes itself as offering "instant liquidity for locked assets" through financial NFTs, lost roughly $2 million to a reentrancy exploit on March 28, 2022. Because the team moved quickly to contain the incident, the damage stayed well below what it could have been — though the protocol still earned a spot at #67 on the rekt leaderboard.

01Timeline of the response

Revest says it first learned of the problem at 2:24 UTC, when the BLOCKS DAO development team flagged the exploit. BLOCKS DAO was not alone in taking losses — EcoFi and RENA Finance were hit as well, since all three projects relied on Revest's vault infrastructure.

The Revest team responded by pausing transfers of the RVST token. That move blocked the attacker's follow-up attempt — made just 70 seconds later — to drain the RVST-ETH liquidity pool on Uniswap, sparing the protocol an additional $1.15 million in losses.

Once the attacker began selling off the stolen tokens, prices for the affected assets collapsed: BLOCKS initially fell more than 95% and remained down around 80% afterward, while ECO dropped roughly 98%. The stolen RENA tokens, by contrast, were left untouched, still sitting in the attacker's wallet. (Analysis credit: @BlockSecTeam.)

02How the exploit worked

The vulnerability traced back to a reentrancy flaw in Revest's ERC1155 minting logic (see an example transaction involving RENA).

Creating a new Smart Vault runs through the mintAddressLock function, which takes, among other inputs, a quantities value and a depositAmount value. When called, Revest Vault triggers the mint function on FNFTHandler, which issues the specified quantities of ERC1155 tokens under the next available fnftId to the designated recipient(s). Burning those tokens later lets a holder claim their share of the underlying locked assets. Each call increments fnftId by one.

Additional deposits into an existing FNFT go through depositAdditionalToFNFT, and are supposed to match the ratio set by quantities — formally, quantity == FNFTHandler.getSupply(fnftId). When that condition fails, the code instead pulls the user's share out of the position and creates a new FNFT, sized using the original position's depositAmount plus whatever was newly deposited.

Sums referenced in this case file

The bug: depositAmount from the existing position gets used before fnftId (tracked through fnftsCreated) is incremented at the close of the minting routine. That gap gave an attacker a window to reenter the contract and pile additional value onto a position that was still technically "in progress."

The attack, step by step:

  1. The attacker called mintAddressLock to create a position with fnftId=1027, depositAmount=0, quantities=[2], using Rena as the asset and a malicious contract as the recipient. Since depositAmount × quantities[0] = 0 × 2 = 0, no actual Rena changed hands.
  2. The attacker called mintAddressLock a second time, opening fnftId=1028 with depositAmount=0 and quantities=360,000, again for Rena, again routed to the malicious contract. As before, zero Rena was transferred, but the attacker walked away holding 360,000 tokens under fnftId=1028 — tokens that, at this point, had no backing value.
  3. Before step 2 finished executing — specifically, during the mint call inside FNFTHandler — the attacker reentered the Revest contract through the onERC1155Received callback. From there, depositAdditionalToFNFT was invoked with amount=1e18, quantities=1, and fnftId=1027. Ordinarily this would have spun up a fresh position at fnftId=1029. But because fnftId hadn't been updated yet, the call instead overwrote position 1028, suddenly giving those attacker-held tokens real backing.
  4. Having deposited only the equivalent of 1 quantity × 1e18 Rena in step 3, the attacker then called withdrawFNFT and pulled out 360,000 × 1e18 Rena tokens.

03What was lost

Per Revest's own post-mortem, the roughly $2 million taken broke down as:

  • 350,000 RENA (about $125k), which remains sitting in the attacker's address
  • 715 million BLOCKS (about $1.7M)
  • 7.7 million ECO (about $100k)

Smaller sums — between $10k and $12k — of ConstitutionDAO and LUKSO tokens were taken too. After converting most of the haul to ETH, the attacker routed the funds through Tornado Cash.

04Aftermath

For a protocol whose core pitch is a secure vault for other projects' tokens, a breach of this kind is a particularly bad look. Revest acknowledged as much, noting that the flaw had slipped past its existing audit from Solidity Finance — prompting the team's own conclusion that a single audit isn't sufficient assurance.

The rapid incident response and the detailed post-mortem that followed were reassuring signs of how the team handled the aftermath. Even so, Revest was candid that it lacks the resources for full financial restitution, while stating an intent to make affected users whole eventually. As of this writing, no concrete plan for how that would happen had been announced.

Revest Finance
Investigation alerts

Get new scam files the moment we publish them — usually 2–3 emails a week.

Enter a valid email address.

No spam, unsubscribe anytime. We never sell your data. Crypto assets are volatile and high-risk; nothing here is financial advice.

You're on the list. Watch your inbox for the next scam file.