Rich Chrome Rattlesnake
Medium
A transaction will revert even when the total supply of stablecoin remains within its minimum and maximum limit due to a logic issue in the StablecoinHandler._verifyStablecoinSwap()
function.
The issue arises in the StablecoinHandler._verifyStablecoinSwap()
function, where it checks if the total supply of the ss.origin
falls below the minimum limit or if the ss.target
exceeds the maximum limit. Here's the relevant portion of the code:
function _verifyStablecoinSwap(
address wallet,
StablecoinSwap memory ss
) internal view nonZero(ss) {
// Ensure the wallet address is not zero.
if (wallet == address(0)) revert ZeroValueInput("WALLET");
// For the origin currency:
if (isXYZ(ss.origin)) {
// Ensure the total supply does not drop below the minimum limit after burning the specified amount.
if (
205: Stablecoin(ss.origin).totalSupply() - ss.oAmount <
getMinLimit(ss.origin)
) revert InvalidMintBurnBoundry(ss.origin, ss.oAmount);
} else if (ss.liquiditySafe == address(0)) {
// Ensure the liquidity safe is provided for ERC20 origin tokens.
revert ZeroValueInput("LIQUIDITY SAFE");
}
// For the target currency:
if (isXYZ(ss.target)) {
// Ensure the total supply does not exceed the maximum limit after minting the specified amount.
if (
217: Stablecoin(ss.target).totalSupply() + ss.tAmount >
getMaxLimit(ss.target)
) revert InvalidMintBurnBoundry(ss.target, ss.tAmount);
} else if (ss.liquiditySafe == address(0)) {
// Ensure the liquidity safe is provided for ERC20 target tokens.
revert ZeroValueInput("LIQUIDITY SAFE");
}
}
Let us consider the case that a user merely send tokens to someone without converting tokens. Then ss.origin
and ss.target
is the same, ss.oAmount
and ss.tAmount
is the same, but the ss.destination
will be different with wallet
. In such a case, no change of the total supply of ss.origin
is expected but the function may revert at L205
or L217
.
ss.origin == ss.target
No response
- Assume the min limit of
eUSD
is200
, the max limit is400
and the total supply is300
. - A user attempts to send
200 eUSD
to another user, and the swapper role callsStablecoinHandler.verifyStablecoinSwap()
function withss.origin = ss.target = eUSD
andss.oAmount = ss.tAmount = 200
. - The function reverts at
L205
because200 - 200 < 300
is true, even though no actual supply change occurs.
Transactions will be reverted unnecessarily even when the total supply remains within acceptable limits, preventing users from sending XYZ tokens.
No response
Modify the StablecoinHandler._verifyStablecoinSwap()
function as follows.
function _verifyStablecoinSwap(
address wallet,
StablecoinSwap memory ss
) internal view nonZero(ss) {
// Ensure the wallet address is not zero.
if (wallet == address(0)) revert ZeroValueInput("WALLET");
// For the origin currency:
if (isXYZ(ss.origin)) {
// Ensure the total supply does not drop below the minimum limit after burning the specified amount.
if (
-- Stablecoin(ss.origin).totalSupply() - ss.oAmount <
++ ss.origin != ss.target && Stablecoin(ss.origin).totalSupply() - ss.oAmount <
getMinLimit(ss.origin)
) revert InvalidMintBurnBoundry(ss.origin, ss.oAmount);
} else if (ss.liquiditySafe == address(0)) {
// Ensure the liquidity safe is provided for ERC20 origin tokens.
revert ZeroValueInput("LIQUIDITY SAFE");
}
// For the target currency:
if (isXYZ(ss.target)) {
// Ensure the total supply does not exceed the maximum limit after minting the specified amount.
if (
-- Stablecoin(ss.target).totalSupply() + ss.tAmount >
++ ss.origin != ss.target && Stablecoin(ss.target).totalSupply() + ss.tAmount >
getMaxLimit(ss.target)
) revert InvalidMintBurnBoundry(ss.target, ss.tAmount);
} else if (ss.liquiditySafe == address(0)) {
// Ensure the liquidity safe is provided for ERC20 target tokens.
revert ZeroValueInput("LIQUIDITY SAFE");
}
}