Lucene search

K
code423n4Code4renaCODE423N4:2023-10-CANTO-FINDINGS-ISSUES-239
HistoryOct 06, 2023 - 12:00 a.m.

Rewards cannot be transferred when calling protocol command

2023-10-0600:00:00
Code4rena
github.com
2
protocol commands
liquidityminingpath
crocswapdex
payable
vulnerability

7.1 High

AI Score

Confidence

Low

Lines of code

Vulnerability details

Summary

Rewards are set up using protocol commands, but it’s entrypoint is not payable.

Impact

Rewards can be set up by protocol authorities using the functions setConcRewards() and setAmbRewards() present in the LiquidityMiningPath contracts. These two are part of the β€œcommand” pattern used in the protocol: the main entrypoint receives commands which are then routed to the proper place using codes.

The protocol command flow starts at the CrocSwapDex contract:

<https://github.com/code-423n4/2023-10-canto/blob/main/canto_ambient/contracts/CrocSwapDex.sol#L103-L106&gt;

103:     function protocolCmd (uint16 callpath, bytes calldata cmd, bool sudo)
104:         protocolOnly(sudo) public payable override {
105:         callProtocolCmd(callpath, cmd);
106:     }

<https://github.com/code-423n4/2023-10-canto/blob/main/canto_ambient/contracts/mixins/ProxyCaller.sol#L22-L28&gt;

22:     function callProtocolCmd (uint16 proxyIdx, bytes calldata input) internal
23:         returns (bytes memory) {
24:         assertProxy(proxyIdx);
25:         (bool success, bytes memory output) = proxyPaths_[proxyIdx].delegatecall(
26:             abi.encodeWithSignature("protocolCmd(bytes)", input));
27:         return verifyCallResult(success, output);
28:     }

The protocolCmd() function checks the call is properly authorized and calls callProtocolCmd(), which then executes a delegatecall to the corresponding implementation, in this case the LiquidityMiningPath contract:

<https://github.com/code-423n4/2023-10-canto/blob/main/canto_ambient/contracts/callpaths/LiquidityMiningPath.sol#L26-L37&gt;

26:     function protocolCmd(bytes calldata cmd) public virtual {
27:         (uint8 code, bytes32 poolHash, uint32 weekFrom, uint32 weekTo, uint64 weeklyReward) =
28:             abi.decode(cmd, (uint8, bytes32, uint32, uint32, uint64));
29: 
30:         if (code == ProtocolCmd.SET_CONC_REWARDS_CODE) {
31:             setConcRewards(poolHash, weekFrom, weekTo, weeklyReward);
32:         } else if (code == ProtocolCmd.SET_AMB_REWARDS_CODE) {
33:             setAmbRewards(poolHash, weekFrom, weekTo, weeklyReward);
34:         } else {
35:             revert("Invalid protocol command");
36:         }
37:     }

While CrocSwapDex::protocolCmd() is payable, its counterpart in LiquidityMiningPath is not. This means that rewards cannot be transferred while setting them up, rejecting any command that has positive callvalue.

Recommendation

Make LiquidityMiningPath::protocolCmd() payable.

-   function protocolCmd(bytes calldata cmd) public virtual {
+   function protocolCmd(bytes calldata cmd) public virtual payable {
        (uint8 code, bytes32 poolHash, uint32 weekFrom, uint32 weekTo, uint64 weeklyReward) =
            abi.decode(cmd, (uint8, bytes32, uint32, uint32, uint64));

        if (code == ProtocolCmd.SET_CONC_REWARDS_CODE) {
            setConcRewards(poolHash, weekFrom, weekTo, weeklyReward);
        } else if (code == ProtocolCmd.SET_AMB_REWARDS_CODE) {
            setAmbRewards(poolHash, weekFrom, weekTo, weeklyReward);
        } else {
            revert("Invalid protocol command");
        }
    }

Assessed type

Payable


The text was updated successfully, but these errors were encountered:

All reactions

7.1 High

AI Score

Confidence

Low