Decentralized video infrastructure protocol powering video in web3's leading social and media applications.
Platform: Code4rena
Start Date: 31/08/2023
End Date: 06/09/2023
Period: 6 days
Status: Completed
Pot Size: $55,000 USDC
Participants: 30
Reporter: liveactionllama
Judge: hickuphh3
Id: 282
League: ETH
Banditx0x | 1/30 | $16,701.04 | 3 | 1 | 1 | 0 | 0 | Grade B | 0 | Grade B |
ladboy233 | 2/30 | $5,454.09 | 3 | 0 | 0 | 2 | 1 | Grade B | 0 | 0 |
bronze_pickaxe | 3/30 | $3,014.31 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
Krace | 4/30 | $2,417.44 | 2 | 1 | 0 | 0 | 0 | 0 | 0 | Grade B |
VAD37 | 5/30 | $2,318.70 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
ether_sky | 6/30 | $2,318.70 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
Vagner | 7/30 | $2,232.82 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
rvierdiiev | 8/30 | $1,048.07 | 2 | 0 | 0 | 1 | 0 | Grade A | 0 | 0 |
ADM | 9/30 | $1,003.03 | 2 | 0 | 0 | 1 | 0 | 0 | 0 | Grade B |
Sathish9098 | 10/30 | $821.21 | 2 | 0 | 0 | 0 | 0 | 0 | Grade A | Grade A |
Auditor per page
Automated findings output for the audit can be found here within 24 hours of audit opening.
Note for C4 wardens: Anything included in the automated findings output is considered a publicly known issue and is ineligible for awards.
Livepeer is a protocol that coordinates an open video streaming infrastructure. The protocol is governed by the LPT token, which is already used to stake on hundreds of transcoding providers and participate in a partially off-chain polling governance process. To learn more about Livepeer check the following resources:
This upgrade creates an onchain community treasury for the Livepeer protocol funded by a percentage of the protocol rewards. It leverages the OpenZeppelin governance primitives with a custom voting power token and counting module to build on top of the existing staking system. The detailed proposals about this upgrade can be found on:
All referenced LIPs can be used as formal specifications for the code in scope.
Here is a video for quick overview of the Livepeer protocol and this audit contest: Livepeer On-Chain Treasury Upgrade Audit Overview
In the video we also show a test explorer to interact with this upgrade. If you are interested in seeing it working on the higher level, feel free to follow this guide.
See scope.txt for a list of all files/contracts in scope. Some contracts already existed in the protocol and were only modified in this upgrade. Check the diff on:
The following contracts should be considered in scope for audit:
Contracts | Lines of Code (and comments) | Purpose | External Libraries used |
---|---|---|---|
contracts/bonding/BondingManager.sol | 888 (567) | Existing contract that manages the protocol bonds (aka staking) and rewards. This upgrade adds support for state checkpointing and treasury rewards minting. It is the most sensitive contract in this contest as it has a critical role in the protocol today. | @openzeppelin/contracts/utils/math/SafeMath.sol |
contracts/bonding/BondingVotes.sol | 272 (224) | Stores checkpoints of the BondingManager state to provide an IERC5805Upgradeable (IVotes ) implementation for the OZ Governor. | @openzeppelin/contracts/utils/Arrays.sol , @openzeppelin/contracts/utils/math/SafeCast.sol |
contracts/bonding/libraries/EarningsPoolLIP36.sol | 60 (26) | This library provides helper functions for calculating staking rewards using the LIP-36 cumulative earnings algorithm. | @openzeppelin/contracts/utils/math/SafeMath.sol |
contracts/bonding/libraries/SortedArrays.sol | 38 (29) | This library provides helpers for maintaining and looking up on sorted arrays. It builds on top of Arrays.findUpperBound to provide an equivalent findLowerBound for checkpoint lookup. | @openzeppelin/contracts/utils/Arrays.sol |
contracts/treasury/GovernorCountingOverridable.sol | 124 (68) | Abstract contract that implements an OZ Governor counting module with support for delegators to override their delegates (transcoders) vote on a proposal. | @openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol , @openzeppelin/contracts-upgradeable/governance/GovernorUpgradeable.sol , @openzeppelin/contracts-upgradeable/interfaces/IERC5805Upgradeable.sol (unused) |
contracts/treasury/Treasury.sol | 12 (10) | This contract inherits from TimelockControllerUpgradeable in order to make it initializable. Used by the governor to hold funds and execute proposals. | @openzeppelin/contracts-upgradeable/governance/TimelockControllerUpgradeable.sol |
contracts/treasury/LivepeerGovernor.sol | 106 (42) | This contract is the actual Governor implementation. It combines the OZ built-in and the custom modules and extensions into a concrete contract that can be instantiated and used. It contains mostly the plumbing to put the pieces together. | @openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol , @openzeppelin/contracts-upgradeable/governance/GovernorUpgradeable.sol , @openzeppelin/contracts-upgradeable/governance/extensions/GovernorVotesUpgradeable.sol , @openzeppelin/contracts-upgradeable/governance/extensions/GovernorVotesQuorumFractionUpgradeable.sol , @openzeppelin/contracts-upgradeable/governance/extensions/GovernorSettingsUpgradeable.sol , @openzeppelin/contracts-upgradeable/governance/extensions/GovernorTimelockControlUpgradeable.sol |
The following interfaces are also relevant as they were created or modified. Even though they contain no logic to be audited, they are included for reference and indirect dependencies:
Interfaces | Lines of Code (and comments) | Purpose | Libraries used |
---|---|---|---|
contracts/bonding/IBondingManager.sol | 68 (16) | Interface for BondingManager . Added a function so it can be called from BondingVotes in the interface. | |
contracts/bonding/IBondingVotes.sol | 28 (13) | Interface for BondingVotes . Inherits from IVotes so it implements the interface expected by the governor. | |
contracts/treasury/IVotes.sol | 9 (2) | Interface extension of IERC5805Upgradeable expected by GovernorCountingOverridable to provide voting power. | @openzeppelin/contracts-upgradeable/interfaces/IERC5805Upgradeable.sol |
The above metrics have all been calculated with cloc
. For further metrics like normalized SLOC and complexity reports see scope-metrics.md (or scope-metrics.html for richer view). The latter were generated with solidity-code-metrics
.
test/
, contracts/test/
or src/test/
are out of scope (but can be used to test the contracts in scope).@openzeppelin/*
)The voting power and governance systems should be entirely separate of the existing protocol contracts with the exception of the BondingManager
contract. This contract was modified to support the treasury contribution and transparently checkpointing the state on the BondingVotes
contract.
BondingManager
behavior apart from the specified ones and their dependencies.BondingManager
checkpointing is extensive and correct. Any change to an account's state should be consistently reflected on the BondingVotes
contract.Livepeer also uses a bespoke staking rewards calculation as defined in LIP-36. While this was not introduced by this upgrade, it is reused in the voting power logic as BondingVotes
needs to calculate historical values for a delegator. The gist of the logic is:
reward()
function on every protocol round.EarningsPool.cumulativeRewardFactor
) stored for every round, corresponding to the current round rewards.As a side note, this reward()
function is also where the treasury rewards are minted in this upgrade.
BondingVotes
will be inconsistent with BondingManager
until a first checkpoint is made for an account.
BondingVotes
contract does not implement ERC-5805
completely. Details can be found in the technical spec.LivepeerGovernor
when a vote is cast cannot be used by generic indexers to calculate the total proposal votes. That because the events will not account for the overrides implemented in GovernorCountingOverridable
, which would need a custom indexing logic.Disconsidering the upgrade step when previously existing accounts are not checkpointed yet:
getVotes
and totalSupply
consistent with the BondingManager
state?getPastVotes
and getPastTotalSupply
match the value returned by getVotes
and totalSupply
in the end of the corresponding round?getPastVotes
and getPastTotalSupply
immutable after the queried round is over?BondingManager
)?controller.owner()
)- If you have a public code repo, please share it here: https://github.com/livepeer/protocol - How many contracts are in scope?: 7 - Total SLoC for these contracts?: 1500 - How many external imports are there?: 16 - How many separate interfaces and struct definitions are there for the contracts within scope?: 6 - Does most of your code generally use composition or inheritance?: Inheritance - How many external calls?: 0 - What is the overall line coverage percentage provided by your tests?: 100% - Is this an upgrade of an existing system?: Yes, to add checkpointing support for an existing staking system, abstract it as an IERC5805 token and set up an OpenZeppelin Governor on top of that. - Check all that apply (e.g. timelock, NFT, AMM, ERC20, rollups, etc.): Uses Timelock from OZ, Deployed on L2 but no bridges involved. - Is there a need to understand a separate part of the codebase / get context in order to audit this part of the protocol?: Yes - Please describe required context: You must be relatively familiar with the existing staking system from Livepeer(BondingManager) in order to verify that the stake checkpoints are being made correctly. It is also useful to be familiar with OpenZeppelin's Governance primitives. - Does it use an oracle?: No - Describe any novel or unique curve logic or mathematical models your code uses: None - Is this either a fork of or an alternate implementation of another project?: No - Does it use a side-chain?: No - Describe any specific areas you would like addressed: - Find any inconsistency in the stake checkpoint with the actual stake in BondingManager in the corresponding round (as per the LIP-89 spec); - Force the vote counting logic to behave differently from the specification, fabricating or losing voting power, altering other users votes (apart from the override), etc; - Exploit the governor/treasury into running arbitrary code without a proper proposal; - Find any loopholes for the LivepeerGovernor to make changes to the protocol itself; - Distort the treasury contribution to something different than what is configured;
yarn
yarn compile
yarn test:audit
BondingVotes
upgrade fork testforge test --match-contract BondingVotesStateInitialization --fork-url https://arbitrum-mainnet.infura.io/v3/$INFURA_KEY -vvv --fork-block-number 110930219
yarn test
yarn test:audit-gas
Notice that this runs all the tests from test:audit
excluding only the unit tests.
yarn test:gas
Notice that this runs only the tests from test/gas-report/*
folder. It is not a super-set of test:audit-gas
.
To deploy on a live network follow the doc/devnet.md guide.
slither contracts
Output provided on slither.txt.
yarn clean
yarn prettier
yarn test:coverage