Wrong fee mechanism in redeemBackSPCT
Description
The redeemBackSPCT
function in the USDz contract redeems USDz tokens to the corresponding SPCT tokens, taking a redemption fee:
function redeemBackSPCT(uint256 _amount) external whenNotPaused checkCollateralRate {
require(_amount > 0, "REDEEM_AMOUNT_IS_ZERO");
require(!_blacklist[msg.sender], "SENDER_IN_BLACKLIST");
// calculate fee with SPCT
if (redeemFeeRate == 0) {
_burnUSDz(msg.sender, _amount);
} else {
uint256 feeAmount = _amount.mul(redeemFeeRate).div(FEE_COEFFICIENT);
uint256 amountAfterFee = _amount.sub(feeAmount);
_burnUSDz(msg.sender, amountAfterFee);
if (feeAmount != 0) {
_transfer(msg.sender, treasury, feeAmount);
}
}
IERC20(address(spct)).safeTransfer(msg.sender, _amount);
emit Redeem(msg.sender, _amount);
}
This function internally transfers the fee to the treasury and burns the rest. However, SPCT tokens of the _amount
, which is the amount that fee is not deducted from, is transferred to the caller.
Impact
A user would be able to redeem their USDz tokens into SPCT tokens without paying the expected fee. This can lead to a mismatch between the total backed SPCT tokens and the minted USDz tokens, breaking the assumption that each USDz token is fully backed by an equivalent amount of SPCT tokens.
Recommendations
If fees are enabled, consider transferring SPCT tokens of the fee-deducted amount using amountAfterFee
.
Remediation
This issue has been acknowledged by Anzen Group Ltd., and a fix was implemented in commit 8c70d55a↗.