syrupUSDC’s re-evaluation
Maple contacted us to re-evaluate the syrupUSDC system after implementing a Timelock contract as the new super admin.
The following outlines the key security concerns we previously raised and details how the Maple team has addressed them, based on our recommendations provided in the conclusion section of the analysis, and a non-exhaustive overview of the new Governor Timelock contract.
Security concerns
1. Globals and system’s contracts upgrades
Previous State:
-
The Globals singleton contract upgrades that are not time-locked have enough rights to modify critical parts of the system in a scenario where the upgradable admin (currently controlled by the Governor) has its signers’ keys exploited by a malicious actor.
-
The Governor + SecurityAdmin pattern can bypass the timelock, which is only enforced when the Pool Delegate initiates the upgradable calls of critical contracts within the system. This could break the system, similar to the scenario above, if a malicious actor gains complete control.
Current State:
Resolved.
The Maple team has transferred the Governor admin (previously a Safe 4-of-7) to the new Governor Timelock, enhancing the system security in terms of upgradability.
The following shows the updated access control risk table of the Maple Globals contract:
| Previous Permission Owner | Current Permission Owner | functions | Criticality | Previous Risk | Current Risk |
|---|---|---|---|---|---|
| Upgradable Admin: Governor | Upgradable Admin: Governor Timelock | setImplementation | CRITICAL | ||
| Governor | Governor Timelock | setPendingGovernor, setDefaultTimelockParameters, setTimelockWindows, unscheduleCall, setMapleTreasury, setMigrationAdmin, setOperationalAdmin, setSecurityAdmin, setPriceOracle, setValidCollateralAsset, setValidPoolAsset, setValidPoolDeployer, setManualOverridePrice | CRITICAL | ||
| Governor or OperationalAdmin - Safe 3-of-5 | Governor Timelock or OperationalAdmin - Safe 3-of-5 | activatePoolManager, setBootstrapMint, setCanDeployFrom, setValidBorrower, setValidInstanceOf, setValidPoolDelegate, setMaxCoverLiquidationPercent, setMinCoverAmount, setPlatformManagementFeeRate, setPlatformOriginationFeeRate, setPlatformServiceFeeRate | HIGH | ||
| Governor or SecurityAdmin - Safe 3-of-6 | Governor Timelock or SecurityAdmin - Safe 3-of-6 | setContractPause, setFunctionUnpause, setProtocolPause | HIGH |
2. Exchange rate manipulation through impairment strategies
Previous State:
- The impairment/disabling strategies action is not time-locked, which could lead to a rapid rate drop, resulting in multiple liquidations and potential bad debt on Aave. A similar scenario could occur if a malicious actor gains control over one of the addresses responsible for this role. We have recommended the Maple team to re-evaluate this flow, to be more defensive, even if keeping the impairment/disabling levers required for the protocol to work.
Current State:
Acknowledged; partially improved.
The Maple team has chosen a different approach in terms of addressing the impairment of strategies (see Maple answer).
The Maple Team uploaded to their GitBook docs a document outlining the entire impairment procedure before any action is taken, which increases transparency about their process.
The following shows the updated access control risk table of the DeFi Strategies:
| Previous Permission Owner | Current Permission Owner | functions | Criticality | Previous Risk | Current Risk |
|---|---|---|---|---|---|
| PoolDelegate - MPC (call time-locked) | PoolDelegate - MPC (call time-locked) | upgrade | CRITICAL | ||
| SecurityAdmin - [Safe 3-of-6] (Address: 0x6b1A78C1...72bD60818 | Etherscan) | SecurityAdmin - [Safe 3-of-6] (Address: 0x6b1A78C1...72bD60818 | Etherscan) (call time-locked on globals) | upgrade | CRITICAL | ||
| factory | factory (call time-locked on globals) | setImplementation, migrate | CRITICAL | ||
| StrategyManager: PoolDelegate - MPC: Syrup Deployer | StrategyManager: PoolDelegate - MPC: Syrup Deployer | fundStrategy, withdrawFromStrategy | HIGH | ||
| ProtocolAdmins: PoolDelegate - MPC: Syrup Deployer, Governor, OperationalAdmin (Safe 3-of-5) | ProtocolAdmins: PoolDelegate - MPC: Syrup Deployer, Governor Timelock, OperationalAdmin (Safe 3-of-5) | deactivateStrategy, impairStrategy, reactivateStrategy, setStrategyFeeRate | HIGH |
*It is outside of the scope of this analysis to evaluate the lending protocol/overcollateralization dynamics (e.g., lending terms), so there can be additional risk.
Governor Timelock
During these improvements, Maple introduced an extra Timelock smart contract to secure their system.
The Governor Timelock is a non-upgradable, role-based timelock contract that enforces a delay before executing calls. The contract provides granular roles for different controlling entities, features a configurable default, and contract-method timelock parameters (delay and execution window), which always enforce a default minimum of 1 day.
| Permission Owner | functions | Criticality | Risk |
|---|---|---|---|
| Governor Timelock | setDefaultTimelockParameters, setFunctionTimelockParameters | HIGH | |
ROLE_ADMIN: Governor 4-of-7 , EOA |
proposeRoleUpdates, setPendingTokenWithdrawer | HIGH | |
PROPOSER_ROLE: Governor 4-of-7 |
scheduleProposals | HIGH | |
EXECUTOR_ROLE: Safe 3-of-5, EOA |
executeProposals | HIGH | |
CANCELLER_ROLE: Safe 3-of-6 |
unscheduleProposals | HIGH | |
| tokenWithdrawer | withdrawERC20Token | MEDIUM |
- Access Control
-
ROLE_ADMINmanages the roles of the Governor timelock by granting or revoking them through theproposeRoleUpdates(bytes[] roles, address[] accs, bool[] grant)function. It also manages thetokenWithdrawerby callingsetPendingTokenWithdrawer(address). It’s important to note that theproposeRoleUpdatesmethod must pass the delay period, whilesetPendingTokenWithdrawerdoes not. -
PROPOSER_ROLEis responsible for schedule calls via thescheduleProposals(address[] targets, bytes[] data)function. -
EXECUTOR_ROLEexecutes the scheduled calls after the delay period has passed and before the window period finishes via theexecuteProposals(uint[] ids, address[] targets, bytes[] data)function -
CANCELLER_ROLEdenies the execution of calls after being scheduled through theunscheduleProposals(uint[] ids)function. It’s important to note that when theROLE_ADMINproposes new roles via theproposeRoleUpdates, they cannot be unscheduled.
-
Miscellaneous
-
The security reviews of the Governor Timelock can be found in their Github repository here.
-
We advised the team to transfer the EOAs with the
ROLE_ADMINandEXECUTOR_ROLEroles to Safe Wallets, to prevent these roles from being controlled by a single private key that could be compromised.
Conclusion
After the improvements, syrupUSDC has enhanced its security in terms of upgradability, and there are no major blockers for listing.
However, we reinforce here that the exchange rate can still be manipulated (by donations and impairing/disabling strategies). If the DAO approves the syrupUSDC listing, the risk teams must be aware of the fragile rate’s behavior before setting the risk parameters recommendations, e-modes, caps, and, most importantly, ensure it is not borrowable.