Platform: Code4rena
Start Date: 01/09/2023
Pot Size: $36,500 USDC
Total HM: 4
Participants: 70
Period: 6 days
Judge: kirk-baird
Id: 281
League: ETH
Rank: 35/70
Findings: 2
Award: $25.93
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: adriro
Also found by: 0x6980, 0xStalin, 0xanmol, 0xmystery, 0xpanicError, Arz, Aymen0909, BenRai, Breeje, Lalanda, MohammedRizwan, Raihan, SovaSlava, Stormreckson, Udsen, ast3ros, bin2chen, castle_chain, catellatech, codegpt, dev0cloo, gkrastenov, hals, klau5, kutugu, ladboy233, matrix_0wl, nirlin, ohm, peanuts, pipidu83, sandy, wahedtalash77
7.08 USDC - $7.08
https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/bridge/DestinationBridge.sol#L255-L275 https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/bridge/DestinationBridge.sol#L144-L146
There must always be more than 0 approvals to withdraw tokens, which breaks protocol logic. In the case of setting 0 approvals, user will not be able to withdraw their funds.
In setThresholds()
, there is a possibility that there is no need for any approvals due to this comment:
* @dev This function will remove all previously set thresholds for a given chain * and will thresholds corresponding to the params of this function. Passing * in empty arrays will remove all thresholds for a given chain */
If that happens, the execute()
function fails to work because of the _attachThreshold()
function. In _attachThreshold()
, if the number of approvals is zero, the function reverts.
if (txnToThresholdSet[txnHash].numberOfApprovalsNeeded == 0) { revert NoThresholdMatch(); }
This means that in setThresholds()
, the numOfApprovers
array must always be more than zero, which means that the amounts
array must be more than zero. There can never be a case when there is zero approvals.
function setThresholds( string calldata srcChain, uint256[] calldata amounts, uint256[] calldata numOfApprovers ) external onlyOwner { if (amounts.length != numOfApprovers.length) { revert ArrayLengthMismatch(); }
Manual Review
The check in _attachThreshold()
needs to be sidestepped if the protocol intends to not have any approval. Probably have another function that has a boolean value that can be toggled by the owner. If toggled, then the function below will not run.
if (txnToThresholdSet[txnHash].numberOfApprovalsNeeded == 0) { revert NoThresholdMatch(); }
Context
#0 - c4-pre-sort
2023-09-08T04:56:18Z
raymondfam marked the issue as duplicate of #273
#1 - c4-pre-sort
2023-09-08T04:56:22Z
raymondfam marked the issue as sufficient quality report
#2 - c4-judge
2023-09-19T10:43:46Z
kirk-baird changed the severity to QA (Quality Assurance)
#3 - c4-judge
2023-09-24T07:29:59Z
kirk-baird marked the issue as grade-b
🌟 Selected for report: catellatech
Also found by: 0xAsen, 0xE1D, 0xStalin, 0xmystery, Breeje, Bube, DedOhWale, JayShreeRAM, K42, Krace, castle_chain, hals, hunter_w3b, kaveyjoe, m4ttm, mahdikarimi, nirlin, peanuts, sandy
18.8458 USDC - $18.85
function getRUSDYByShares(uint256 _shares) public view returns (uint256) { return (_shares * oracle.getPrice()) / (1e18 * BPS_DENOMINATOR); }
_checkAndUpdateInstantMintLimit(txn.amount);
function burn( address _account, uint256 _amount ) external onlyRole(BURNER_ROLE) { uint256 sharesAmount = getSharesByRUSDY(_amount); _burnShares(_account, sharesAmount); usdy.transfer(msg.sender, sharesAmount / BPS_DENOMINATOR);
function addApprover(address approver) external onlyOwner { approvers[approver] = true; emit ApproverAdded(approver); }
function pause() external onlyOwner { _pause(); } /** * @notice Admin function to unpause the contract * * @dev Only used for bridge functions */ function unpause() external onlyOwner { _unpause();
14 hours
#0 - c4-pre-sort
2023-09-08T14:48:16Z
raymondfam marked the issue as sufficient quality report
#1 - c4-judge
2023-09-24T07:05:26Z
kirk-baird marked the issue as grade-b