Platform: Code4rena
Start Date: 19/01/2024
Pot Size: $36,500 USDC
Total HM: 9
Participants: 113
Period: 3 days
Judge: 0xsomeone
Id: 322
League: ETH
Rank: 69/113
Findings: 1
Award: $12.28
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Kaysoft
Also found by: 0xmystery, Aamir, DadeKuma, IceBear, Pechenite, SBSecurity, Shaheen, bronze_pickaxe, ether_sky, nobody2018, rjs, rouhsamad, slvDev, zxriptor
12.2818 USDC - $12.28
Missing checks for address(0) issue can be found in automated findings, but here it could lead to a DoS, so two scenarios are described:
https://github.com/code-423n4/2024-01-decent/blob/main/src/UTBFeeCollector.sol#L18
/** * @dev Sets the signer used for fee verification. * @param _signer The address of the signer. */ function setSigner(address _signer) public onlyOwner { signer = _signer; }
This would fail to pass through splitSignature and render collectFees() unusable.
function setRouter(address _router) public { router = _router; }
setRouter lack access control Anyone can set themselves as the router and pass through onlyRouter(). Can mint or burn tokens arbitrarily.
Do not hardcode useZro to false when estimating fees, pass it as a parameter instead. https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L142
dcntEth.estimateSendAndCallFee( _dstChainId, destinationBridge, _amount, _payload, _dstGasForCall, false, // useZero adapterParams // Relayer adapter parameters // contains packet type (send and call in this case) and gasAmount );
See point 6 in this integration checklist provided by the LayerZero team.
Layer Zero acknowledges that a cross-chain call can use more or less gas than the standard 200k. https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L96
uint256 GAS_FOR_RELAY = 100000; uint256 gasAmount = GAS_FOR_RELAY + _dstGasForCall;
Adjust to 200,000 gas.
Ensure that callBridge in StargateBridgeAdapter can execute as expected. https://github.com/code-423n4/2024-01-decent/blob/main/src/bridge_adapters/StargateBridgeAdapter.sol#L170
function callBridge( uint256 amt2Bridge, uint256 dstChainId, bytes memory bridgePayload, bytes calldata additionalArgs, address payable refund ) private { router.swap{value: msg.value}( getDstChainId(additionalArgs), //lzBridgeData._dstChainId, // send to LayerZero chainId getSrcPoolId(additionalArgs), //lzBridgeData._srcPoolId, // source pool id getDstPoolId(additionalArgs), //lzBridgeData._dstPoolId, // dst pool id refund, // refund adddress. extra gas (if any) is returned to this address amt2Bridge, // quantity to swap (amt2Bridge * (10000 - SG_FEE_BPS)) / 10000, // the min qty you would accept on the destination, fee is 6 bips getLzTxObj(additionalArgs), // additional gasLimit increase, airdrop, at address abi.encodePacked(getDestAdapter(dstChainId)), bridgePayload // bytes param, if you wish to send additional payload you can abi.encode() them here ); }
Currently using msg.value in router.swap, to ensure that bridge() can be executed as expected. Use quoteLayerZeroFee() to get the fee required to call swap(). The fee ensures the cross chain message is paid for. Use it as the { value: xxxx } passed to the actual swap() method when you perform the swap.
#0 - raymondfam
2024-01-26T06:46:06Z
L-02 to #14
5 L
#1 - c4-pre-sort
2024-01-26T06:46:10Z
raymondfam marked the issue as sufficient quality report
#2 - alex-ppg
2024-02-04T22:49:02Z
The Warden's QA report has been graded B based on a score of 26
combined with a manual review per the relevant QA guideline document located here.
The Warden's submission's score was assessed based on the following accepted findings:
#3 - c4-judge
2024-02-04T22:49:05Z
alex-ppg marked the issue as grade-b
#5 - alex-ppg
2024-02-06T17:27:49Z
Hey @iceBearRobot, thanks for contributing to the PJQA discussion! The severity of both findings has been misjudged as low and specifically L-04 does not detail why this is an issue. As such, I will not award them as duplicates of the referenced exhibits.