Aerodrome
Stage 1
Website

Protocol Decentralization

Stage 0
Stage 1
Stage 2

  • Upgrades with potential of “loss of funds or unclaimed yield” not protected with onchain governance AND Exit Window >= 30 days
  • There are no external dependencies
  • Alternative third-party frontends exist

Risk Areas

Chain
Upgrades
Autonomy
Exit Window
Access

Summary

Aerodrome Finance is a next-generation AMM designed to serve as Base's central liquidity hub, combining a powerful liquidity incentive engine, vote-lock governance model, and friendly user experience. Aerodrome inherits the latest features from Velodrome V2.

Ratings

Chain

Aerodrome is deployed on the Base chain, an Ethereum L2 in Stage 1 according to L2BEAT.

Chain score: Medium

Upgradeability

To a large part the protocol is immutable. In particular, no permissions with a potential impact on user funds have been identified.

The remaining permissions are related to the protocol's rewards system and periphery contracts. These permissions are controlled by a number of multisigs including an undeclared multisig.

Among these, the undeclared multisig has control over a whitelist of special voters with the ability to change the rewards distributed to LPs. Specifically, "regular" veNFT holders compete in weekly voting rounds to distribute a fixed amount of rewards, paid in the protocol's native token, AERO. Regular voters are able to signal their support for a specific gauge which, after the conclusion of a voting round, receives and distributes rewards among the LPs of the linked pool. This public voting period is followed by a "private" voting window of 1 hour during which only the whitelisted veNFT holders are able to participate. As a result, these whitelisted veNFT holders, and by extension the undeclared multisig, are able to control the final vote outcome. The impact of this is classified as a potential material change of the expected performance including the loss of accrued yield (if public votes are overwritten by the whitelisted veNFTs).

The undeclared multisig further is the owner of various contracts, and the associated permissions, including the FactoryRegistry. This contract allows the undeclared multisig to (un-) approve factory contracts within the protocol. User's swaps are routed through the pools created from the approved factories. Users are protected from malicious factories (and pools) through a user defined slippage tolerance which is enforced on all swaps on the router contract. On the other hand, only pools created from the default factory are enabled for LP provisioning functions effectively protecting LPs in the protocol.

Another noteworthy permission in the protocol is the ability to kill and revive gauges and thereby stop, or enable, a gauge to receive and distribute rewards to LPs and voters. However, killing a gauge does not affect the rewards already distributed to LPs or voters and also does not affect the rewards, or any other aspect, of other gauges. This permission hence can not materially affect the protocol's expected performance.

Upgradeability score: Medium

Autonomy

Aerodrome does not have external dependencies 🎉

Autonomy score: Low

Exit Window

Existing permissions have a "Medium" risk score and are not protected by an exit window. Users are not able to withdraw funds in case of an unwanted update.

Exit Window score: Medium

Accessibility

Aerodrome provides multiple access points for users, including both centralized interfaces (aerodrome.finance, alt.aerodrome.finance) and decentralized interfaces on IPFS (aero.drome.eth, aero.drome.eth.limo, aero.drome.eth.link). This diversity in user interfaces ensures redundancy, allowing users to access the protocol even if one interface becomes unavailable.

Accessibility score: Low

Conclusion

The Aerodrome protocol achieves Medium centralization risk scores for its Upgradeability and Exit Window dimensions. It thus ranks Stage 1.

The protocol could reach Stage 2 by transferring the permissions to an onchain governance with 30 days Exit Window.

Overall score: Stage 1

Reviewer Notes

There were no particular discoveries made during the analysis of this protocol.

Protocol Analysis

The killing of a gauge

After each period, AERO tokens from the Minter contract flow into the Voter contract via calling updatePeriod(). Once the tokens are in the Voter contract, they flow according to the voting weight to each Gauge through calling distribute() on the Voter contract. Once the AERO tokens ended up in the different Gauge contracts, the users can claim their reward no matter of the living status of the Gauge. It's the function call distribute() that sends the tokens to the Gauge which reverts if the Gauge is killed. For rewards to be claimable for users the function calls updatePeriod() and distribute() need to occur in succession and the killing of the Gauge before either one of them results in yield not being available to the user. But, since both functions are public everyone, can call them. And thus during the first block of each period where updatePeriod() is callable, the permission owner that kills the Gauge needs to frontrun the transactions which are calling updatePeriod() and distribute(). This centralisation vector is thus not definitive and only probabilistic.

On the other hand, Voters earn a claim on yield proportional to their allocated votes when calling the vote() for a gauge on the Voter contract. Function vote() will revert if the respective gauge is killed, thus not crediting a claim on yield for the killed gauge. However, previous votes and the credited yield claims, before the gauge is killed, are not affected by this. Voters will thus still be able to claim their accumulated yield.

Dependencies

No external dependency has been found.

Governance

The permissions in Aerodrome are held by the multisigs highlighted below.

Security Council

NameAccountType≥ 7 signers≥ 51% threshold≥ 50% non-insiderSigners public
Aerodrome Foundation and Incentives0xBDE0c70BdC242577c52dFAD53389F82fd149EA5aMultisig 3/5
Public Goods Fund0x834C0DA026d5F933C2c18Fa9F8Ba7f1f792fDa52 Multisig 3/5
Emergency Council0x99249b10593fCa1Ae9DAE6D4819F1A6dae5C013DMultisig 3/5
Undeclared Multisig0xE6A41fE61E7a1996B59d508661e3f524d6A32075Multisig 3/7

Info sourced from here: https://aerodrome.finance/security#emergency.

Exit Window

No timelocks have been found protecting the various permissioned functions in the protocol. All updates take effect immediately.

Contracts & Permissions

Contracts

All Permission Owners

NameAccountType
Aerodrome Foundation and Incentives0xBDE0c70BdC242577c52dFAD53389F82fd149EA5aMultisig 3/5
Public Goods Fund0x834C0DA026d5F933C2c18Fa9F8Ba7f1f792fDa52 Multisig 3/5
Emergency Council0x99249b10593fCa1Ae9DAE6D4819F1A6dae5C013DMultisig 3/5
Undeclared Multisig0xE6A41fE61E7a1996B59d508661e3f524d6A32075Multisig 3/7

Permissions

ContractFunctionImpactOwner
AEROsetMinterSets the minter for the AERO token.Minter contract 0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5 (immutable)
AEROmintAllows the permission owner to mint new AERO tokens into existence.Minter contract 0xeB018363F0a9Af8f91F06FEe6613a751b2A33FE5
AirdropDistributorrenounceOwnershipRenounces the ownership and disables all functions gated by onlyOwner modifier.0x0 (renounced)
AirdropDistributortransferOwnershipTransfers ownership to another address that is not the 0-address.0x0 (renounced)
AirdropDistributordistributeTokensDistributes permanently locked NFTs to the desired addresses (airdrop).0x0 (renounced)
FactoryRegistryrenounceOwnershipRenounces ownership and disables all functions gated by onlyOwner modifier.Undeclared Multisig
FactoryRegistrytransferOwnershipTransfers ownership to another address that is not the 0-address.Undeclared Multisig
FactoryRegistryapproveThis function allows the permission owner to approve a set of factories used in Aerodrome Protocol. The Router contract (0xcF77a3Ba9A5CA399B7c97c74d54e5b1Beb874E43) checks whether the submitted factory is approved with the function isPoolFactoryApproved exposed by the FactoryRegistry. If a factory is approved, the router allows swaps on the pools from this factory. LiquidityManagement (addLiquidity() or removeLiquidity()) is not affected, as it only allows pools from the original PoolFactory 0x420DD381b31aEf6683db6B902084cB0FFECe40DaUndeclared Multisig
FactoryRegistryunapproveThis function allows permission owner to unapprove a set of factories used in the Aerodrome Porotocol. As a consequence pools from these unapproved factories cannot be used for swaps called on the main router (0xcF77a3Ba9A5CA399B7c97c74d54e5b1Beb874E43).Undeclared Multisig
FactoryRegistrysetManagedRewardsFactoryThe permission owner can set the managed rewards factory as default for managed positions. This factory is used by the VotingEscrow contract to generate rewards for users that have a managed ve position (veNFT contract looks up the registered ManagedRewardsFactory inside createManagedLockFor). The reward contracts deployed from the ManagedRewardsFactory expose getReward function which could be a malicious implementation (not paying out rewards for managed positions after calling setManagedRewardsFactory with a malicious factory).Undeclared Multisig
MintersetTeamAssigns the team role to a specific address which can call setTeamRate.Aerodrome Foundation and Incentives multisig
MinteracceptTeamTransfers the team address to the role pendingTeam.Currently, no address has the role pendingTeam
MintersetTeamRateChanges the team's percentage, capped to a maximum of 500 basis points (5%).Aerodrome Foundation and Incentives multisig
MinternudgeAllows epoch governor to modify the tail emission rate within specific bounds. Tail emissions continue to reward LPs after the initial reward emissions decayed below a certain threshold. The tail emissions rate can be nudged by at most 1 basis point per epoch to a maximum of 100 basis points or to a minimum of 1 basis point.Undeclared Multisig
PoolFactorysetVoterSets a new voter for all pools deployed after that.Contract voter 0x16613524e02ad97eDfeF371bC883F2F5d6C480A5 (immutable)
PoolFactorysetPauserSets a pauser for all pools deployed with this factory. The pauser can halt the swaps for these pools.Undeclared Multisig
PoolFactorysetPauseStateSets or removes the paused state of the factory. This affects swaps.Undeclared Multisig
PoolFactorysetFeeManagerDesignates a new address to be the FeeManager. The FeeManager can call setFee and setCustomFee.Undeclared Multisig
PoolFactorysetFeeSets a new fee for all future deployed fees, within a maximum of 100 basis points.Undeclared Multisig
PoolFactorysetCustomFeeSets a custom fee for a specific pool, capped at 3%.Undeclared Multisig
VotersetGovernorSets a new governor. Governor alone owns the permission to call setEpochGovernor, setMaxVotingNum, whitelistToken and whitelistNFT on the Voter contract.Undeclared Multisig
VotersetEpochGovernorSets a new epoch-based governor. Epoch governor can call nudge on Minter contract to modify the tail emission rate by at most 1 basis point per epoch to a maximum of 100 basis points or to a minimum of 1 basis point.Undeclared Multisig
VotersetEmergencyCouncilSets a new emergency council which can call killGauge and reviveGauge. See Upgradability section for more details.Emergency Council Multisig
VotersetMaxVotingNumSets a maximum number of pools a user can vote for. Code enforces that this number is not below 10.Undeclared Multisig
VoterwhitelistTokenWhitelists (or unwhitelists) a token for use in bribes. If not whitelisted, no gauge can be created for a pool and thus the pool cannot participate in the reward distribution as it cannot receive votes.Undeclared Multisig
VoterwhitelistNFTWhitelists (or unwhitelists) a token ID for voting in the last hour prior to epoch flip.Undeclared Multisig
VoterkillGaugeKills a gauge, preventing new emissions and deposits, but allowing withdrawals (see "Notes regarding the killing of a gauge").Emergency Council Multisig
VoterreviveGaugeRevives a killed gauge, allowing it to receive emissions and deposits again (see "Notes regarding the killing of a gauge").Emergency Council Multisig
VotingEscrowcreateManagedLockForManager can create a managed ve position for a user (a permanent lock).AllowedManager or Governor Undeclared Multisig
VotingEscrowdepositManagedDelegates balance to a managed NFT, re-locking it to the maximum lock time on withdrawal.Voter contract 0x16613524e02ad97eDfeF371bC883F2F5d6C480A5
VotingEscrowwithdrawManagedRetrieves locked rewards and withdraws balance from managed NFT.Voter contract 0x16613524e02ad97eDfeF371bC883F2F5d6C480A5
VotingEscrowsetAllowedManagerPermits one address to call createManagedLockFor() that is not the governor.Governor (Undeclared Multisig)
VotingEscrowsetManagedStateSets Managed NFT state. Inactive NFTs cannot be deposited into.Emergency Council Multisig or Governor (Undeclared Multisig)
VotingEscrowsetVoterAndDistributorSets Voter and distributor reference in this contract.Voter contract 0x16613524e02ad97eDfeF371bC883F2F5d6C480A5
VotingEscrowvotingSets voted for _tokenId to true or false.Voter contract 0x16613524e02ad97eDfeF371bC883F2F5d6C480A5
NonfungiblePositionManagersetTokenDescriptorSets a new token descriptor.Undeclared Multisig
NonfungiblePositionManagersetOwnerSets a new owner for the contract. The only permission the owner has is to change the token descriptor.Undeclared Multisig
CLFactorysetOwnerSets a new owner for the pool factory. The only permission the owner role has on this contract is to call enableTickSpacing which enables a certain tick spacing with a default associated fee.Undeclared Multisig
CLFactorysetSwapFeeManagerThe SwapFeeManager can set a new SwapFeeManager. The SwapFeeManager can call setSwapFeeModule.Undeclared Multisig
CLFactorysetUnstakedFeeManagerThe UnstakedFeeManager can set a new UnstakedFeeManager. The UnstakedFeeManager can call setUnstakedFeeModule.Undeclared Multisig
CLFactorysetSwapFeeModuleSets a new swap fee module for all the pools deployed by the factory. This fee module indicates the fee for a certain swap based on the pool. The fee is capped to 0.1% max irrespective of the fee module.SwapFeeManager (Undeclared Multisig)
CLFactorysetUnstakedFeeModuleUpdates the unstaked fee module for all the pools deployed by the factory. This fee module indicates the fee for unstaking based on the pool. The fee is capped to 1% max irrespective of the fee module.UnstakeFeeManager (Undeclared Multisig)
CLFactorysetDefaultUnstakedFeeUpdates the default unstaked fee of the factory.UnstakeFeeManager (Undeclared Multisig)
CLFactoryenableTickSpacingEnables a certain tickSpacing in the pools deployed from the factory.Undeclared Multisig
CustomSwapFeeModulesetCustomFeeSets a custom fee between 0 and a max fee for a specified pool. The CLFactory gets the fee via calling getFee on this contract.SwapFeeManager (Undeclared Multisig)
CustomUnstakedFeeModulesetCustomFeeSets a custom fee between 0 and a max fee for a specified pool. The CLFactory gets the fee via calling getFee on this contract.UnstakeFeeManager (Undeclared Multisig)