Basic Lilac Marmot
High
function debondAndLock(address _pod, uint256 _amount) external nonReentrant {
require(_amount > 0, "D1");
require(_pod != address(0), "D2");
IERC20(_pod).safeTransferFrom(_msgSender(), address(this), _amount);
IDecentralizedIndex _podContract = IDecentralizedIndex(_pod);
IDecentralizedIndex.IndexAssetInfo[] memory _podTokens = _podContract.getAllAssets();
address[] memory _tokens = new address[](_podTokens.length);
uint256[] memory _balancesBefore = new uint256[](_tokens.length);
**// Get token addresses and balances before debonding
for (uint256 i = 0; i < _tokens.length; i++) {
_tokens[i] = _podTokens[i].token;
_balancesBefore[i] = IERC20(_tokens[i]).balanceOf(address(this));
}
_podContract.debond(_amount, new address[](0), new uint8[](0));
uint256[] memory _receivedAmounts = new uint256[](_tokens.length);
for (uint256 i = 0; i < _tokens.length; i++) {
_receivedAmounts[i] = IERC20(_tokens[i]).balanceOf(address(this)) - _balancesBefore[i];
}**
...
}
The debondAndLock
function is designed to deposit a specific token. Since the _pod
parameter can have an arbitrary address, the return value of the getAllAssets
function can also vary depending on the address. If the getAllAssets
function returns duplicate addresses, a single deposit could result in multiple values for _receivedAmounts
. As a result, the deposited amount could be withdrawn multiple times, creating a vulnerability that allows multiple withdrawals from a single deposit.
function _withdraw(address _user, uint256 _lockId) internal {
LockInfo storage _lock = locks[_lockId];
require(_lock.user == _user, "W1");
require(!_lock.withdrawn, "W2");
require(block.timestamp >= _lock.unlockTime, "W3");
_lock.withdrawn = true;
for (uint256 i = 0; i < _lock.tokens.length; i++) {
if (_lock.amounts[i] > 0) {
**IERC20(_lock.tokens[i]).safeTransfer(_user, _lock.amounts[i]);**
}
}
emit TokensWithdrawn(_lockId, _user, _lock.tokens, _lock.amounts);
}
Since there is no validation for duplicate addresses, as described above, it becomes possible to make multiple withdrawals.
in PodUnwrapLocker.sol:74
there is a missing check on token duplication
No response
No response
- Deploy a contract that implements the transferFrom, getAllAssets, and debond functions.
- Call the debondAndLock function and set the _pod parameter to the address of the contract deployed in step 1.
- Withdraw the duplicate tokens through the earlyWithdraw function.
The affected party will lose all assets.
No response
// Get token addresses and balances before debonding
for (uint256 i = 0; i < _tokens.length; i++) {
_tokens[i] = _podTokens[i].token;
**for(uint256 j=i+1; j<_tokens.length; j++) require(_tokens[i] != _tokens[j], "invalid same token");**
_balancesBefore[i] = IERC20(_tokens[i]).balanceOf(address(this));
}
performs checks to verify the token quantity and ensure that the same token is being used.