Platform: Code4rena
Start Date: 18/02/2022
Pot Size: $125,000 USDC
Total HM: 13
Participants: 24
Period: 14 days
Judge: GalloDaSballo
Total Solo HM: 6
Id: 88
League: ETH
Rank: 10/24
Findings: 4
Award: $3,245.99
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: IllIllI
Also found by: gzeon, kirk-baird
1618.2353 USDC - $1,618.24
After a schain is killed by both the owner and the IMA admin, schain admin can control all the fund using e.g. DepositBoxERC20.getFunds
functions. This pose a significant centralization risk after the schain is killed.
function getFunds(string calldata schainName, address erc20OnMainnet, address receiver, uint amount) external override onlySchainOwner(schainName) whenKilled(keccak256(abi.encodePacked(schainName))) { bytes32 schainHash = keccak256(abi.encodePacked(schainName)); require(transferredAmount[schainHash][erc20OnMainnet] >= amount, "Incorrect amount"); _removeTransferredAmount(schainHash, erc20OnMainnet, amount); require( ERC20Upgradeable(erc20OnMainnet).transfer(receiver, amount), "Transfer was failed" ); }
Require both the owner and IMA admin on the fund distribution process.
#0 - cstrangedk
2022-03-09T00:09:30Z
Issue here incorrectly assumes that the owner is a centralized authority. SKALE Chain owners may be a DAO, multisig, or single owner - the IMA bridge is agnostic to, and cannot control the governance structure adopted in each SKALE Chain. The responsibility and process conducted after kill is executed rests on the Owner and whatever governance structure is adopted.
#1 - GalloDaSballo
2022-06-01T18:32:35Z
Dup of #76
🌟 Selected for report: 0x1f8b
Also found by: IllIllI, cmichel, gzeon, kirk-baird
786.4623 USDC - $786.46
The transfered amount is saved without checking the actual amount of token received after the transfer.
_saveTransferredAmount(schainHash, erc20OnMainnet, amount); require( ERC20Upgradeable(erc20OnMainnet).transferFrom( msg.sender, address(this), amount ), "Transfer was failed" );
Check before and after balance
#0 - cstrangedk
2022-03-04T00:38:55Z
Duplicate and disputed of #42
#1 - GalloDaSballo
2022-06-01T16:50:21Z
Dup of #50
SKALE chains operate in a gas-free environment using a native gas token called sFUEL. sFUEL has no economic value and is allocated from the SKALE chain owner
It is possible for schain owner to censor user / freeze user fund by not distributing enough sFUEL
Since the base Tx gas cost is 21000, some global minimum can be hardcoded to avoid misconfiguration https://github.com/skalenetwork/ima-c4-audit/blob/11d6a6ae5bf16af552edd75183791375e501915f/contracts/mainnet/CommunityPool.sol#196
Recommended to upgrade to latest Solidity 0.8.12
contracts/schain/CommunityLocker.sol:219: // TODO: uncomment when oracle finished
Some of the decode function is not adjacent to its encode counterpart, which make reading the code a bit annoying (e.g. encodeTransferErc20Message and decodeTransferErc20Message) https://github.com/skalenetwork/ima-c4-audit/blob/11d6a6ae5bf16af552edd75183791375e501915f/contracts/Messages.sol
DepositBoxERC20.depositERC20()
did not check if amount!=0
https://github.com/skalenetwork/ima-c4-audit/blob/11d6a6ae5bf16af552edd75183791375e501915f/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol
#0 - DimaStebaev
2022-03-14T14:07:25Z
Agreed.
#1 - GalloDaSballo
2022-05-05T14:42:53Z
Given that this is effectively a design decision, I agree with Low Severity
Agree with lack of validation given rational values
Would have liked to see this finding more developed
In lack of explanation I am not going to count this finding
That's like, your opinion man.
Valid
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, CertoraInc, TerrierLover, Tomio, WatchPug, d4rk, gzeon, kenta, kyliek, m_smirnova2020, rfa, robee, saian, ye0lde
> 0
is less efficient than != 0
for uint in require conditionRef: https://twitter.com/GalloDaSballo/status/1485430908165443590 https://github.com/skalenetwork/ima-c4-audit/blob/11d6a6ae5bf16af552edd75183791375e501915f/contracts/mainnet/DepositBoxes/DepositBoxEth.sol#L122
require(approveTransfers[msg.sender] > 0, "User has insufficient ETH");
uint userWalletBal = _userWallets[user][schainHash]; if (amount > userWalletBal) { amount = userWalletBal; _userWallets[user][schainHash] = 0; }else{ _userWallets[user][schainHash] = userWalletBal - amount; }
uint userWalletBal = _userWallets[msg.sender][schainHash]; require(amount <= userWalletBal, "Balance is too low"); require(!messageProxy.messageInProgress(), "Message is in progress"); _userWallets[msg.sender][schainHash] = userWalletBal - amount;
The keccak256(abi.encodePacked("Mainnet"))
can be precalculated as constant
https://github.com/skalenetwork/ima-c4-audit/blob/11d6a6ae5bf16af552edd75183791375e501915f/contracts/mainnet/DepositBox.sol
It is a bit wasteful to use string schainName as input and hash it repeatedly onchain
Can save some gas by skiping the balance check and let it revert during the transfer https://github.com/skalenetwork/ima-c4-audit/blob/11d6a6ae5bf16af552edd75183791375e501915f/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol#L157
require(ERC20Upgradeable(message.token).balanceOf(address(this)) >= message.amount, "Not enough money");
#0 - yavrsky
2022-03-14T15:06:18Z
Only marginal gas improvements.
#1 - GalloDaSballo
2022-04-28T16:40:44Z
Saves 3 gas
100 gas saved * 2 = 200
Saves 30 gas for the calculation
Would have liked to see further detail here, as there's potential downsides to applying this advice, for this reason will not give it any points
Agree, this would save STATICCALL + the Storage check = 200 gas
#2 - GalloDaSballo
2022-04-28T16:40:58Z
Total Gas Saved 433