Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: low
Invalid

Missing Token Recovery Mechanism

Summary

The DEToken contract lacks functionality to recover accidentally sent tokens. When ERC20 tokens other than RToken are mistakenly sent to the contract, they become permanently locked.

Vulnerability Details

The contract only handles RToken transfers through transferAsset() but has no mechanism to recover other ERC20 tokens. This is particularly problematic since the contract is meant to interact with multiple tokens in the RAAC ecosystem.

POC (Proof of Concept)

const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("DEToken Token Recovery Vulnerability", function () {
let DEToken, deToken;
let MockERC20, mockToken;
let owner, user;
beforeEach(async function () {
[owner, user] = await ethers.getSigners();
// Deploy mock ERC20 token
MockERC20 = await ethers.getContractFactory("MockERC20");
mockToken = await MockERC20.deploy("Mock", "MCK");
// Deploy DEToken
DEToken = await ethers.getContractFactory("DEToken");
deToken = await DEToken.deploy(
"Debitum Emptor",
"DE",
owner.address,
mockToken.address // Using mock token as rToken for testing
);
// Mint some mock tokens to user
await mockToken.mint(user.address, ethers.utils.parseEther("100"));
});
it("should demonstrate tokens can be locked in contract", async function () {
// User accidentally sends tokens to DEToken contract
await mockToken.connect(user).transfer(
deToken.address,
ethers.utils.parseEther("10")
);
// Verify tokens are stuck in contract
expect(await mockToken.balanceOf(deToken.address))
.to.equal(ethers.utils.parseEther("10"));
// No way to recover tokens
// This would fail if we tried to implement a recovery function
await expect(
deToken.connect(owner).transfer(
owner.address,
ethers.utils.parseEther("10")
)
).to.be.revertedWith("OnlyStabilityPool");
});
});

Impact

Severity: Low

  • Permanent loss of accidentally transferred tokens

  • No administrative recovery mechanism

  • Could affect protocol's ability to handle emergencies

  • Risk increases with protocol adoption and multi-token interactions

Tools Used

  • Hardhat testing framework

  • Manual code review

Recommendations

  1. Add token recovery functionality:

contract DEToken is ERC20, ERC20Permit, IDEToken, Ownable {
// ...existing code...
error CannotRescueRToken();
event TokenRescued(address token, address to, uint256 amount);
/**
* @notice Recovers ERC20 tokens accidentally sent to contract
* @param token Address of token to recover
* @param to Address to send recovered tokens to
* @param amount Amount of tokens to recover
*/
function rescueToken(
address token,
address to,
uint256 amount
) external onlyOwner {
if (token == rTokenAddress) revert CannotRescueRToken();
if (to == address(0)) revert InvalidAddress();
if (amount == 0) revert InvalidAmount();
IERC20(token).safeTransfer(to, amount);
emit TokenRescued(token, to, amount);
}
}
  1. Add rescue function test:

it("should allow owner to rescue accidentally sent tokens", async function () {
// Setup different token for testing
const OtherToken = await ethers.getContractFactory("MockERC20");
const otherToken = await OtherToken.deploy("Other", "OTH");
await otherToken.mint(user.address, ethers.utils.parseEther("100"));
// User accidentally sends tokens
await otherToken.connect(user).transfer(
deToken.address,
ethers.utils.parseEther("10")
);
// Owner should be able to rescue tokens
await expect(
deToken.connect(owner).rescueToken(
otherToken.address,
owner.address,
ethers.utils.parseEther("10")
)
)
.to.emit(deToken, "TokenRescued")
.withArgs(
otherToken.address,
owner.address,
ethers.utils.parseEther("10")
);
// Verify tokens were recovered
expect(await otherToken.balanceOf(owner.address))
.to.equal(ethers.utils.parseEther("10"));
});
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!