Reward tokens belonging to BalancedVault will be stuck in the Incentivizer contract
Summary
A product can create multiple incentive programs. Each incentive program has a corresponding reward token. Every time Incentivizer.syncAccount is called, all reward tokens will be accumulated for the account. BalancedVault is actually the maker of the product, and it is a user for the product. Whenever BalancedVault.sync() is called by off-chain keeper, BalancedVault's reward tokens will be accumulated. The larger the position, the more reward tokens you will get. As the maker of the product, BalancedVault must be a user with a large position. However, BalancedVault did not implement the interface to claim these reward tokens, resulting in a large number of reward tokens being left in the Incentivizer contract.
Vulnerability Detail
Let's take a look at the flow of the BalancedVault.sync() function.
BalancedVault.sync()
_rebalance(context, UFixed18Lib.ZERO) //L148 in BalancedVault.sol
_rebalancePosition(context, claimAmount); //L433 in BalancedVault.sol
_updateMakerPosition(markets(marketId).long, targetPosition); //L489 in BalancedVault.sol
_updateMakerPosition(markets(marketId).short, targetPosition); //L490 in BalancedVault.sol
product.closeMake //L508 in BalancedVault.sol
product.openMake //L517 in BalancedVault.sol
When the position needs to be adjusted, product.openMake/closeMake will trigger Product._settleAccount. The flow of the function is as follows:
Product._settleAccount //L154 in Product.sol
_controller.incentivizer().syncAccount(account, settleOracleVersion) //L167 in Product.sol
_products[product].syncAccount(product, account, currentOracleVersion) //L130 in Incentivizer.sol
// Settle programs
uint256[] memory activeProgramIds = self.activeProgramsFor[account].values();
for (uint256 i; i < activeProgramIds.length; i++) {
uint256 programId = activeProgramIds[i];
Program storage program = self.programs[programId];
-> program.settle(product, self.programInfos[programId], account, currentOracleVersion);
if (!self.activePrograms.contains(programId) && currentOracleVersion.version >= program.versionComplete) {
self.activeProgramsFor[account].remove(programId);
}
}
The Incentivizer contract provides a claim interface for users to claim all reward tokens. However, there is no code in BalancedVault.sol to call Incentivizer.claim.
Impact
This will result in a large amount of reward tokens being stuck in the Incentivizer contract.
nobody2018
high
Reward tokens belonging to BalancedVault will be stuck in the Incentivizer contract
Summary
A product can create multiple incentive programs. Each incentive program has a corresponding reward token. Every time
Incentivizer.syncAccount
is called, all reward tokens will be accumulated for the account. BalancedVault is actually the maker of the product, and it is a user for the product. WheneverBalancedVault.sync()
is called by off-chain keeper, BalancedVault's reward tokens will be accumulated. The larger the position, the more reward tokens you will get. As the maker of the product, BalancedVault must be a user with a large position. However, BalancedVault did not implement the interface to claim these reward tokens, resulting in a large number of reward tokens being left in the Incentivizer contract.Vulnerability Detail
Let's take a look at the flow of the
BalancedVault.sync()
function.When the position needs to be adjusted,
product.openMake/closeMake
will triggerProduct._settleAccount
. The flow of the function is as follows:There is a [for](https://github.com/sherlock-audit/2023-05-perennial/blob/main/perennial-mono/packages/perennial/contracts/incentivizer/types/ProductManager.sol#L124-L131) loop in
ProductManager.syncAccount
that will accumulate all reward tokens for the account.The Incentivizer contract provides a
claim
interface for users to claim all reward tokens. However, there is no code in BalancedVault.sol to callIncentivizer.claim
.Impact
This will result in a large amount of reward tokens being stuck in the Incentivizer contract.
Code Snippet
https://github.com/sherlock-audit/2023-05-perennial/blob/main/perennial-mono/packages/perennial/contracts/incentivizer/Incentivizer.sol#L138-L143
https://github.com/sherlock-audit/2023-05-perennial/blob/main/perennial-mono/packages/perennial/contracts/incentivizer/Incentivizer.sol#L125-L131
Tool used
Manual Review
Recommendation
Add interface to BalancedVault to claim reward tokens.
Duplicate of #43