Salty Powder Sealion
Medium
The core swap functions (StablecoinHandler::_stablecoinSwap
and AmirX::swap
) lack explicit approval checks for tokens being transferred, despite the protocol specification requiring such checks.
https://github.com/sherlock-audit/2024-11-telcoin/blob/main/telcoin-audit/contracts/stablecoin/StablecoinHandler.sol#L144
https://github.com/sherlock-audit/2024-11-telcoin/blob/main/telcoin-audit/contracts/swap/AmirX.sol#L73
The root cause is a design oversight where the protocol relies on implicit approval checks through safeTransferFrom
failures rather than implementing explicit pre-flight approval validation.
-
SWAPPER_ROLE
needs to callstablecoinSwap()
orswap()
with valid parameters. -
Contract needs to be unpaused
No response
- SWAPPER_ROLE calls the swap functions.
- Functions attempts
safeTransferFrom
without checking approvals - Transaction reverts due to insufficient allowance
- Transactions will silently revert if approvals aren't set
- Poor user experience
- Wasted gas on failed transactions
- Violates protocol specification
No response
Adding explicit approval check:
function _stablecoinSwap(address wallet, StablecoinSwap memory ss) internal {
if (ss.stablecoinFeeCurrency != address(0) && ss.stablecoinFeeSafe != address(0)) {
+ require(ERC20(ss.stablecoinFeeCurrency).allowance(wallet, address(this)) >= ss.feeAmount,
"Insufficient fee token allowance"
);
ERC20PermitUpgradeable(ss.stablecoinFeeCurrency).safeTransferFrom(
wallet, ss.stablecoinFeeSafe, ss.feeAmount
);
}
if (isXYZ(ss.origin)) {
+ require(ERC20(ss.origin).allowance(wallet,address(this))>=ss.oAmount,"Insufficient origin token allowance"
Stablecoin(ss.origin).burnFrom(wallet, ss.oAmount);
} else {
ERC20PermitUpgradeable(ss.origin).safeTransferFrom(wallet, ss.liquiditySafe, ss.oAmount);
}
if (isXYZ(ss.target)) {
Stablecoin(ss.target).mintTo(ss.destination, ss.tAmount);
} else {
ERC20PermitUpgradeable(ss.target).safeTransferFrom(ss.liquiditySafe, ss.destination, ss.tAmount);
}
}
```