[ARFC] Onboard syrupUSDC to Aave V3 Core Instance

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 :red_circle: :green_circle:
Governor Governor Timelock setPendingGovernor, setDefaultTimelockParameters, setTimelockWindows, unscheduleCall, setMapleTreasury, setMigrationAdmin, setOperationalAdmin, setSecurityAdmin, setPriceOracle, setValidCollateralAsset, setValidPoolAsset, setValidPoolDeployer, setManualOverridePrice CRITICAL :red_circle: :green_circle:
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 :red_circle: :green_circle:
Governor or SecurityAdmin - Safe 3-of-6 Governor Timelock or SecurityAdmin - Safe 3-of-6 setContractPause, setFunctionUnpause, setProtocolPause HIGH :green_circle: :green_circle:

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 :green_circle: :green_circle:
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 :yellow_circle: :green_circle:
factory factory (call time-locked on globals) setImplementation, migrate CRITICAL :yellow_circle: :green_circle:
StrategyManager: PoolDelegate - MPC: Syrup Deployer StrategyManager: PoolDelegate - MPC: Syrup Deployer fundStrategy, withdrawFromStrategy HIGH :yellow_circle:* :yellow_circle:*
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 :red_circle: :red_circle:

*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 :green_circle:
ROLE_ADMIN: Governor 4-of-7 , EOA proposeRoleUpdates, setPendingTokenWithdrawer HIGH :yellow_circle:
PROPOSER_ROLE: Governor 4-of-7 scheduleProposals HIGH :green_circle:
EXECUTOR_ROLE: Safe 3-of-5, EOA executeProposals HIGH :yellow_circle:
CANCELLER_ROLE: Safe 3-of-6 unscheduleProposals HIGH :green_circle:
tokenWithdrawer withdrawERC20Token MEDIUM :green_circle:

  • Access Control
    • ROLE_ADMIN manages the roles of the Governor timelock by granting or revoking them through the proposeRoleUpdates(bytes[] roles, address[] accs, bool[] grant) function. It also manages the tokenWithdrawer by calling setPendingTokenWithdrawer(address). It’s important to note that the proposeRoleUpdates method must pass the delay period, while setPendingTokenWithdrawer does not.

    • PROPOSER_ROLE is responsible for schedule calls via the scheduleProposals(address[] targets, bytes[] data) function.

    • EXECUTOR_ROLE executes the scheduled calls after the delay period has passed and before the window period finishes via the executeProposals(uint[] ids, address[] targets, bytes[] data) function

    • CANCELLER_ROLE denies the execution of calls after being scheduled through the unscheduleProposals(uint[] ids) function. It’s important to note that when the ROLE_ADMIN proposes new roles via the proposeRoleUpdates, 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_ADMIN and EXECUTOR_ROLE roles 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.