A security mechanism in which stakers commit LINK in smart contracts to back certain performance guarantees around oracle services.
Platform: Code4rena
Start Date: 25/08/2023
End Date: 12/09/2023
Period: 18 days
Status: Awarded
Pot Size: $250,000 USDC
Participants: 104
Id: 270
League: ETH
MiloTruck | 1/104 | $48,797.95 | 11 | 0 | 0 | 10 | 2 | - | 0 | 0 |
immeas | 2/104 | $16,263.43 | 4 | 0 | 0 | 3 | 1 | - | 0 | 0 |
BitMinds | 3/104 | $16,199.43 | 3 | 0 | 0 | 1 | 1 | - | 0 | - |
sashik_eth | 4/104 | $16,005.26 | 4 | 0 | 0 | 3 | 1 | 0 | 0 | - |
HE1M | 5/104 | $10,193.14 | 9 | 0 | 0 | 7 | 0 | - | 0 | - |
Kow | 6/104 | $8,561.60 | 5 | 0 | 0 | 5 | 0 | 0 | 0 | 0 |
pep7siup | 7/104 | $7,169.75 | 3 | 0 | 0 | 2 | 0 | - | 0 | 0 |
0x73696d616f | 8/104 | $6,820.77 | 4 | 0 | 0 | 3 | 0 | - | 0 | 0 |
mert_eren | 9/104 | $5,525.65 | 3 | 0 | 0 | 2 | 0 | - | 0 | 0 |
carrotsmuggler | 10/104 | $5,525.31 | 2 | 0 | 0 | 2 | 0 | 0 | 0 | 0 |
Auditor per page
IMPORTANT NOTE: Prior to receiving payment from this audit you MUST become a Certified Contributor (successfully complete KYC). You do not have to become certified before submitting bugs. But you must successfully complete the certification process within 30 days of the audit end date in order to receive awards. This applies to all audit participants including wardens, teams, bot crews, judges, lookouts, and scouts.
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.
We are releasing several new contracts to support Staking v0.2, which is the second iteration of Chainlink Staking. An overview blog of Staking v0.2 can be found here.
To learn more about Chainlink Staking and the technical design, please check out the following resources:
See scope.txt
Specific focus should be paid to the contracts listed below:
Contract | Description | Lines of Code (and comments) | Libraries used | External contracts called |
---|---|---|---|---|
src/Migratable.sol | Abstract contract that contracts can inherit to make the migratable | 28(7) | ||
src/MigrationProxy.sol | Intermediary contract to handle migrations from v0.1. This contract exists as the v0.1 only accepts a single migration target. | 87 (63) | LinkToken , OperatorStakingPool , CommunityStakingPool , PausableWithAccessControl | |
src/PausableWithAccessControl.sol | Abstract contract that contracts can inherit from in order to make themselves pausable. In addition to extending OpenZeppelin's Pausable contract, this contract also introduces the PAUSER role, which an address must have in order to pause/unpause a contract. | 18 (6) | @openzeppelin/contracts/access/AccessControlDefaultAdminRules.sol, @openzeppelin/contracts/security/Pausable.sol | |
src/alerts/PriceFeedAlertsController.sol | Alerts controller contract defining the logic around when alerts can be raised when the downtime threshold for a feed is met. | 304 (212) | @openzeppelin/contracts/utils/Checkpoints.sol | OperatorStakingPool , CommunityStakingPool , PausableWithAccessControl , Chainlink Feed EACAggregatorProxy |
src/pools/CommunityStakingPool.sol | The v0.2 community staking pool that will hold the LINK community stakers have staked. | 75 (49) | @openzeppelin/contracts/utils/cryptography/MerkleProof.sol | OperatorStakingPool |
src/pools/OperatorStakingPool.sol | The v0.2 node operator staking pool that will hold the LINK Node Operator Stakers have staked. | 308 (214) | @openzeppelin/contracts/utils/Checkpoints.sol , @openzeppelin/contracts/utils/math/Math.sol | RewardVault |
src/pools/StakingPoolBase.sol | Abstract contract that defines the logic shared by the CommunityStakingPool and OperatorStakingPool contracts. | 438 (241) | @openzeppelin/contracts/utils/Checkpoints.sol , @openzeppelin/contracts/utils/math/SafeCast.sol | LINKToken |
src/rewards/RewardVault.sol | The reward vault is the contract that defines the earned rewards calculation logic. This contract also holds all LINK rewards funded by the contract manager. | 1002 (525) | @openzeppelin/contracts/utils/math/SafeCast.sol , @openzeppelin/contracts/utils/math/Math.sol , @solmate/utils/FixedPointMathLib.sol | LINKToken , OperatorStakingPool , CommunityStakingPool |
src/timelock/StakingTimelock.sol | The staking timelock contract is the contract that administers operational changes to the other staking contracts. Any operational transaction will need to be executed through this address after a timelock period. | 87 (28) | OperatorStakingPool , CommunityStakingPool , PriceFeedAlertsController , RewardVault | |
src/timelock/Timelock.sol | This is the base timelock contract that StakingTimelock inherits from and defines all the timelock logic to propose, execute and cancel transactions. | 191 (256) | @openzeppelin/contracts/utils/structs/EnumerableSet.sol |
Contract | Description |
---|---|
src/interfaces/*.sol | Interfaces, contains no logic. Provided for reference. |
src/tests/*.sol | Mock and helper contracts for testing purposes only. |
test/*.sol | Foundry unit, fuzz and invariant tests. |
scripts/*.sol | Foundry deployment scripts |
src/staking-v0.1/ | v0.1 contracts only used in tests |
External libraries |
Term | Description |
---|---|
Node Operator Staker | An entity that is contributing to the decentralized oracle network (DON) operations by running Chainlink node software. Also referred to as Operators. These stakers will only be allowed to stake in the OperatorStakingPool . |
Community Staker | A Chainlink token holder who is not an Operator that is a participant of Staking v0.2. These stakers will only be allowed to stake in the CommunityStakingPool . |
Staker | A staker (a Node Operator or Community Staker) who stakes in a Staking v0.2 pool |
Alerter | A staker who raises a feed downtime alert on-chain. |
Allowlist | A list of Ethereum addresses that will be allowed to stake in the CommunityStakingPool before General Access. |
Base Reward | A Staking Reward for stakers is made available at a rate as defined in the RewardVault contract. The amount of base rewards a staker earns is equal to the amount of total amount of rewards made available to the pool multiplied by their share of the pool relative to other stakers of the same type. |
Delegation Reward | A proportion of Base Rewards from Community Staker rewards that is divided proportionally between all Operators who have staked at least the minimum required amount. |
Aggregate Reward Rate | This parameter expresses the amount of rewards that become available to all stakers per second. This value is then made available to the Community Stakers and Operators in proportion to their pool sizes. |
Ramp Up Multiplier | A staker-specific value that determines how much reward a staker can claim at the current time. Grows linearly from 0 to 1x. |
Unbonding Period | A period of time stakers are required to wait before unstaking. |
Claim Period | The period of time following the unbonding period in which a staker may unstake their tokens. |
Reward Duration | The period of time an amount of rewards are made available for. |
Timelock Period | The period of time after a transaction is proposed in the Timelock before the transaction can be executed. |
The team's largest concerns with the Staking V0.2 protocol are around
OperatorStakingPool
?RewardVault
?MAX_MULTIPLIER
- If you have a public code repo, please share it here: NA - How many contracts are in scope?: 10 - Total SLoC for these contracts?: 2538 - How many external imports are there?: 8. This is the number of unique external libraries used and the unique number of external contracts that Staking v0.2 contracts interact with - How many separate interfaces and struct definitions are there for the contracts within scope?: 10 interfaces 20 structs - Does most of your code generally use composition or inheritance?: Inheritance - How many external calls?: 2. Staking v0.2 makes external calls to the LINK token and Chainlink Price Feeds - What is the overall line coverage percentage provided by your tests?: 100% - Is this an upgrade of an existing system?: Yes. This is the second iteration of Chainlink's Staking protocol - Check all that apply (e.g., timelock, NFT, AMM, ERC20, rollups, etc.): Timelock, ERC-20 Token, Chainlink Price Feeds - 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 may need to understand how Chainlink Price Feeds work in order to understand how the `PriceFeedAlertsController` detects feed downtime. Price data values can be read by calling the feed's `getLatestRoundData` function. The `PriceFeedAlertsController` calls this function to retrieve the time the feed was last updated and compares it against the current `block.timestamp` to determine if the feed has been down for longer than the configured alertable threshold. Additionally you may also need to understand how rewards are migrated from Staking v0.1. - Does it use an oracle?: No but the PriceFeedAlertsController reads the last updated at time from Chainlink Data Feeds. - Describe any novel or unique curve logic or mathematical models your code uses: The `RewardVault` calculates staker rewards by implementing the widely used reward-per-token model implemented by other staker protocols. A more detailed explanation of this can be found in the Staking Reward Calculations document. - 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: - Reward calculation and the logic in the RewardVault - Upgradability patterns
NOTE: Run the commands below from the root of the project directory
Compile the smart contracts with Forge:
forge build
forge fmt
Run unit tests:
forge test
Run integration tests:
FOUNDRY_PROFILE=integration forge test
Run invariant tests:
FOUNDRY_PROFILE=invariant forge test
Run a single test:
forge test test/MyContract.test.ts
Generate a test coverage report:
pnpm coverage
Unit test coverage is at 100%.
Delete the output smart contract artifacts directory and clears the Forge cache:
forge clean
You can find a .gas-snapshot
file for several key flows. You may find it helpful during gas golfing.
pnpm gas
forge doc --serve
Run Slither with slither src
The output is provided, see slither.txt