TempleGold

TempleDAO
Foundry
25,000 USDC
View results
Submission Details
Severity: high
Invalid

`DaiGoldAuction::recoverToken` cannot recover TempleGold token due to constraints

Description

The DaiGoldAuction::recoverToken function allows privileged accounts to recover ERC20 tokens from the smart contract, including TempleGold, if the auction has not started. However, since startTime is only set at the beginning of an auction, it will never satisfy the condition if (info.startTime == 0). Furthermore, due to other conditions that become true once the auction starts or ends, it becomes impossible to recover any TempleGold. Currently, the only way to bypass these conditions is during the cooldown period, if it is not set to zero.

/**
@> * @notice Recover auction tokens for last but not started auction.
...
*/
function recoverToken(
...
) external override onlyElevatedAccess {
...
if (token != address(templeGold)) {
emit CommonEventsAndErrors.TokenRecovered(to, token, amount);
IERC20(token).safeTransfer(to, amount);
return;
}
// auction started but cooldown pending
uint256 epochId = _currentEpochId;
EpochInfo storage info = epochs[epochId];
@> if (info.startTime == 0) {
revert InvalidOperation();
}
@> if (info.isActive()) {
revert AuctionActive();
}
@> if (info.hasEnded()) {
revert AuctionEnded();
}
...
templeGold.safeTransfer(to, amount);
}

Risk

Likelyhood: High

  • TempleGold recovery will never be possible except during the cooldown period (which, according to the documentation, does not seem to be the intended behavior).

Impact: High

  • Inability to recover TempleGold results in funds being stuck in the contract.

Proof of Concept

Foundry PoC to add in DaiGoldAuction.t.sol

function test_failToRecoverToken_TempleGold() public {
_setVestingFactor(templeGold);
skip(1 days);
vm.startPrank(executor);
templeGold.mint();
uint256 mintAmount = templeGold.balanceOf(address(daiGoldAuction));
// Before starting the auction: revert
vm.expectRevert(
abi.encodeWithSelector(IAuctionBase.InvalidOperation.selector)
);
daiGoldAuction.recoverToken(address(templeGold), alice, mintAmount);
IDaiGoldAuction.AuctionConfig memory _config = _getAuctionConfig();
daiGoldAuction.setAuctionConfig(_config);
_startAuction();
IAuctionBase.EpochInfo memory info = daiGoldAuction.getEpochInfo(1);
// Once auction is started: revert
vm.warp(info.startTime);
vm.expectRevert(
abi.encodeWithSelector(IAuctionBase.AuctionActive.selector)
);
daiGoldAuction.recoverToken(address(templeGold), alice, mintAmount);
// Once auction is ended: revert
vm.warp(info.endTime);
templeGold.mint();
vm.expectRevert(abi.encodeWithSelector(IAuctionBase.AuctionEnded.selector));
daiGoldAuction.recoverToken(address(templeGold), alice, mintAmount);
// Only way is go back in time or during the cooldown
vm.warp(info.startTime - 10 seconds);
mintAmount = info.totalAuctionTokenAmount;
daiGoldAuction.recoverToken(address(templeGold), alice, mintAmount);
vm.stopPrank();
}

Recommended Mitigation

Remove the following condition :

- if (info.startTime == 0) {
- revert InvalidOperation();
- }

If recovery during the cooldown period is not intended, also check the block.timestamp to prevent it.

Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Appeal created

n0kto Submitter
about 1 year ago
n0kto Submitter
about 1 year ago
n0kto Submitter
about 1 year ago
n0kto Submitter
about 1 year ago
inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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