Nutty Licorice Crocodile
Medium
In the AmirX::defiToStablecoinSwap
function, parameter validation is performed at the start. Initially, _verifyDefiSwap
is called to validate the DeFi swap parameters, followed by _verifyStablecoinSwap
for the stablecoin swap validation.
After parameter checks, the function retrieves the current balance of the wallet
for the ss.origin
token. The DeFi swap is then executed, and the function calculates the difference in the wallet
balance before and after the swap to determine the new origin amount, oAmount
.
However, this approach poses a potential issue: if the computed oAmount
exceeds the expected value set in _verifyStablecoinSwap
, it could violate an intended invariant.
A similar issue may also exist in the swap
function.
In AmirX::defiToStablecoinSwap
, the code calculates the wallet
balance before and after executing the defiSwap
as follows:
uint256 iBalance = ERC20(ss.origin).balanceOf(wallet);
_defiSwap(wallet, defi);
uint256 fBalance = ERC20(ss.origin).balanceOf(wallet);
The output amount, oAmount
, is then adjusted based on the difference between fBalance
and iBalance
.
However, this approach may lead to a violation of the minSupply
invariant, which is enforced in _verifyStablecoinSwap
for the origin
token based on the original balance. Adjusting oAmount
later can bypass the intended minSupply
constraint, as the minSupply
check will not reflect the updated balance.
No response
No response
- The
AmirX::defiToStablecoinSwap
operation is called withToken A
as theorigin
currency. - Initially,
Token A
has a supply of 100, with aminSupply
threshold of 90 enforced by_verifyStablecoinSwap
. The initialoAmount
passed is 9, so_verifyStablecoinSwap
passes, as the remaining supply would be 91 (100 - 9 > 90). - The function then proceeds to execute
_defiSwap
. If the balance difference before and after the swap forToken A
is 12, the value ofoAmount
is updated to 12. - This adjustment results in an inconsistent state, as the effective supply of
Token A
drops below theminSupply
threshold of 90, violating the intended supply constraint.
The protocol enters an inconsistent state where the origin
stablecoin used in the swap ends up with a supply lower than the minSupply
threshold set in StablecoinHandler::UpdateXYZ
. This discrepancy violates the minSupply
constraint. Such a state could affect system integrity and potentially allow for unintended behavior, as the minSupply limit is designed to ensure adequate liquidity and stability for that stablecoin.
No response
Consider move the check for _verifyStablecoinSwap
after changing the oAmount
:
function defiToStablecoinSwap(
address wallet,
StablecoinSwap memory ss,
DefiSwap memory defi
) external payable onlyRole(SWAPPER_ROLE) whenNotPaused {
// checks if defi will fail
_verifyDefiSwap(wallet, defi);
// checks if stablecoin swap will fail
_verifyStablecoinSwap(wallet, ss);
//check balance to adjust second swap
uint256 iBalance = ERC20(ss.origin).balanceOf(wallet);
_defiSwap(wallet, defi);
uint256 fBalance = ERC20(ss.origin).balanceOf(wallet);
ss.oAmount = fBalance - iBalance;
+ _verifyStablecoinSwap(wallet, ss);
//change balance to reflect change
_stablecoinSwap(wallet, ss);
}
....
function swap(
address wallet,
bool directional,
StablecoinSwap memory ss,
DefiSwap memory defi
) external payable onlyRole(SWAPPER_ROLE) whenNotPaused {
// checks if it will fail
if (ss.destination != address(0)) _verifyStablecoinSwap(wallet, ss);
if (defi.walletData.length != 0) _verifyDefiSwap(wallet, defi);
if (directional) {
// if only defi swap
if (ss.destination == address(0)) _defiSwap(wallet, defi);
else {
// if defi then stablecoin swap
//check balance to adjust second swap
uint256 iBalance = ERC20(ss.origin).balanceOf(wallet);
if (defi.walletData.length != 0) _defiSwap(wallet, defi);
uint256 fBalance = ERC20(ss.origin).balanceOf(wallet);
//change balance to reflect change
if (fBalance - iBalance != 0) ss.oAmount = fBalance - iBalance;
+ _verifyStablecoinSwap(wallet, ss);
_stablecoinSwap(wallet, ss);
}
} else {
// if stablecoin swap
_stablecoinSwap(wallet, ss);
// if only stablecoin swap
if (defi.walletData.length != 0) _defiSwap(wallet, defi);
}
}