Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions contracts/ConsumerHost.sol
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ contract ConsumerHost is Initializable, OwnableUpgradeable, IConsumer, ERC165, S
* @param controller The address of controller account, consumer to set
*/
function setControllerAccount(address controller) external {
_requireNotBlacklisted(settings, msg.sender);
_requireNotBlacklisted(settings, controller);

controllers[msg.sender] = controller;

emit SetControllerAccount(msg.sender, controller);
Expand All @@ -158,6 +161,8 @@ contract ConsumerHost is Initializable, OwnableUpgradeable, IConsumer, ERC165, S
* @notice consumer call to remove the controller account.
*/
function removeControllerAccount() public {
_requireNotBlacklisted(settings, msg.sender);

address controller = controllers[msg.sender];
delete controllers[msg.sender];

Expand Down Expand Up @@ -221,6 +226,8 @@ contract ConsumerHost is Initializable, OwnableUpgradeable, IConsumer, ERC165, S
* @notice Approve host can use consumer balance
*/
function approve() external {
_requireNotBlacklisted(settings, msg.sender);

require(
!(IEraManager(settings.getContractAddress(SQContracts.EraManager)).maintenance()),
'G019'
Expand All @@ -234,6 +241,8 @@ contract ConsumerHost is Initializable, OwnableUpgradeable, IConsumer, ERC165, S
* @notice Disapprove host can use consumer balance
*/
function disapprove() external {
_requireNotBlacklisted(settings, msg.sender);

require(
!(IEraManager(settings.getContractAddress(SQContracts.EraManager)).maintenance()),
'G019'
Expand All @@ -249,6 +258,8 @@ contract ConsumerHost is Initializable, OwnableUpgradeable, IConsumer, ERC165, S
* @param isApprove approve consumer host agent to act on user's behalf
*/
function deposit(uint256 amount, bool isApprove) external {
_requireNotBlacklisted(settings, msg.sender);

require(
!(IEraManager(settings.getContractAddress(SQContracts.EraManager)).maintenance()),
'G019'
Expand All @@ -273,6 +284,9 @@ contract ConsumerHost is Initializable, OwnableUpgradeable, IConsumer, ERC165, S
* @param _for account
*/
function depositFor(uint256 _amount, address _for) external {
_requireNotBlacklisted(settings, msg.sender);
_requireNotBlacklisted(settings, _for);

require(
!(IEraManager(settings.getContractAddress(SQContracts.EraManager)).maintenance()),
'G019'
Expand All @@ -292,6 +306,8 @@ contract ConsumerHost is Initializable, OwnableUpgradeable, IConsumer, ERC165, S
* @param amount the amount
*/
function withdraw(uint256 amount) external {
_requireNotBlacklisted(settings, msg.sender);

require(
!(IEraManager(settings.getContractAddress(SQContracts.EraManager)).maintenance()),
'G019'
Expand Down Expand Up @@ -320,6 +336,9 @@ contract ConsumerHost is Initializable, OwnableUpgradeable, IConsumer, ERC165, S
) external {
require(msg.sender == settings.getContractAddress(SQContracts.StateChannel), 'G011');
(address consumer, bytes memory sign) = abi.decode(callback, (address, bytes));
_requireNotBlacklisted(settings, consumer);
_requireNotBlacklisted(settings, sender);

if (channels[channelId] == address(0)) {
channels[channelId] = consumer;
} else {
Expand Down Expand Up @@ -364,6 +383,7 @@ contract ConsumerHost is Initializable, OwnableUpgradeable, IConsumer, ERC165, S
require(msg.sender == settings.getContractAddress(SQContracts.StateChannel), 'G011');

address consumer = channels[channelId];
_requireNotBlacklisted(settings, consumer);
Consumer storage info = consumers[consumer];
info.balance += amount;

Expand Down Expand Up @@ -428,6 +448,7 @@ contract ConsumerHost is Initializable, OwnableUpgradeable, IConsumer, ERC165, S
require(msg.sender == settings.getContractAddress(SQContracts.StateChannel), 'G011');
address consumer;
(consumer, ) = this.decodeConsumerCallback(callback);
_requireNotBlacklisted(settings, consumer);
channels[channelId] = consumer;
}

Expand Down
24 changes: 24 additions & 0 deletions contracts/RewardsBooster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ contract RewardsBooster is Initializable, OwnableUpgradeable, IRewardsBooster, S
/// @dev MODIFIER
/// @notice only consumer or its controller can call
modifier consumerAuthorised(address consumer) {
_requireNotBlacklisted(settings, consumer);

if (msg.sender != consumer) {
bool isController = IConsumerRegistry(
settings.getContractAddress(SQContracts.ConsumerRegistry)
Expand Down Expand Up @@ -236,6 +238,8 @@ contract RewardsBooster is Initializable, OwnableUpgradeable, IRewardsBooster, S
bytes32 _deploymentId,
uint256 _amount
) external onlyRegisteredDeployment(_deploymentId) {
_requireNotBlacklisted(settings, msg.sender);

// migrate deployment pool
ProjectType projectType = migrateDeploymentBoost(_deploymentId, msg.sender);

Expand Down Expand Up @@ -277,6 +281,8 @@ contract RewardsBooster is Initializable, OwnableUpgradeable, IRewardsBooster, S
* @param _amount the added amount
*/
function removeBoosterDeployment(bytes32 _deploymentId, uint256 _amount) external {
_requireNotBlacklisted(settings, msg.sender);

// migrate deployment pool
ProjectType projectType = migrateDeploymentBoost(_deploymentId, msg.sender);
require(
Expand All @@ -288,6 +294,15 @@ contract RewardsBooster is Initializable, OwnableUpgradeable, IRewardsBooster, S
IERC20(settings.getContractAddress(SQContracts.SQToken)).safeTransfer(msg.sender, _amount);
}

function adminRemoveBoosterDeployment(
bytes32 _deploymentId,
address _account,
uint256 _amount
) external onlyOwner {
ProjectType projectType = migrateDeploymentBoost(_deploymentId, _account);
_removeBoosterDeployment(projectType, _deploymentId, _account, _amount);
}

/**
* @notice swap booster from one deployment to another
* @param account the account booster the deployments
Expand Down Expand Up @@ -979,6 +994,8 @@ contract RewardsBooster is Initializable, OwnableUpgradeable, IRewardsBooster, S
}

function collectAllocationReward(bytes32 _deploymentId, address _runner) external override {
_requireNotBlacklisted(settings, _runner);

IIndexerRegistry indexerRegistry = IIndexerRegistry(
ISettings(settings).getContractAddress(SQContracts.IndexerRegistry)
);
Expand Down Expand Up @@ -1317,10 +1334,17 @@ contract RewardsBooster is Initializable, OwnableUpgradeable, IRewardsBooster, S
function spendQueryRewards(
bytes32 _deploymentId,
address _spender,
address _runner,
uint256 _amount,
bytes calldata _data
) external override returns (uint256) {
require(msg.sender == settings.getContractAddress(SQContracts.StateChannel), 'RB006');
_requireNotBlacklisted(settings, _spender);
require(
IProjectRegistry(settings.getContractAddress(SQContracts.ProjectRegistry))
.isDeploymentRegistered(_deploymentId),
'RB052'
);
migrateDeploymentBoost(_deploymentId, _spender);

uint256 spend1 = _spendQueryRewards(_deploymentId, _spender, _amount, _data);
Expand Down
20 changes: 20 additions & 0 deletions contracts/RewardsDistributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ contract RewardsDistributor is IRewardsDistributor, Initializable, OwnableUpgrad
settings.getContractAddress(SQContracts.ServiceAgreementRegistry)
).getClosedServiceAgreement(agreementId);
require(agreement.consumer != address(0), 'SA001');
_requireNotBlacklisted(settings, agreement.consumer);
_requireNotBlacklisted(settings, agreement.indexer);

IEraManager eraManager = IEraManager(settings.getContractAddress(SQContracts.EraManager));

address runner = agreement.indexer;
Expand Down Expand Up @@ -303,6 +306,10 @@ contract RewardsDistributor is IRewardsDistributor, Initializable, OwnableUpgrad
uint256 amount,
uint256 era
) external {
_requireNotBlacklisted(settings, msg.sender);
_requireNotBlacklisted(settings, sender);
_requireNotBlacklisted(settings, runner);

require(era <= _getCurrentEra(), 'RD001');
require(era >= info[runner].lastClaimEra, 'RD002');
IERC20(settings.getContractAddress(SQContracts.SQToken)).safeTransferFrom(
Expand All @@ -328,6 +335,8 @@ contract RewardsDistributor is IRewardsDistributor, Initializable, OwnableUpgrad
* @notice check if the current Era is claimed.
*/
function collectAndDistributeRewards(address runner) public {
_requireNotBlacklisted(settings, runner);

Comment on lines 337 to +339
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid freezing distributor accounting for blacklisted runners.

These two functions are bookkeeping entrypoints, not runner-authenticated actions. Rejecting them on runner means accSQTPerStake never advances for that runner again, so non-blacklisted delegators can get stuck with already-earned rewards and unsettled stake changes.

Suggested fix
 function collectAndDistributeRewards(address runner) public {
-    _requireNotBlacklisted(settings, runner);
-
     // check current era is after lastClaimEra
     uint256 currentEra = _getCurrentEra();
     require(info[runner].lastClaimEra < currentEra - 1, 'RD003');
     collectAndDistributeEraRewards(currentEra, runner);
 }
@@
 function collectAndDistributeEraRewards(
     uint256 currentEra,
     address runner
 ) public returns (uint256) {
-    _requireNotBlacklisted(settings, runner);
-
     RewardInfo storage rewardInfo = info[runner];
     require(rewardInfo.lastClaimEra > 0, 'RD004');

Also applies to: 351-356

// check current era is after lastClaimEra
uint256 currentEra = _getCurrentEra();
require(info[runner].lastClaimEra < currentEra - 1, 'RD003');
Expand All @@ -343,6 +352,8 @@ contract RewardsDistributor is IRewardsDistributor, Initializable, OwnableUpgrad
uint256 currentEra,
address runner
) public returns (uint256) {
_requireNotBlacklisted(settings, runner);

RewardInfo storage rewardInfo = info[runner];
require(rewardInfo.lastClaimEra > 0, 'RD004');
// skip when it has been claimed for currentEra - 1, no throws
Expand Down Expand Up @@ -429,13 +440,18 @@ contract RewardsDistributor is IRewardsDistributor, Initializable, OwnableUpgrad
* @notice Claim rewards of msg.sender for specific runner.
*/
function claim(address runner) public {
_requireNotBlacklisted(settings, msg.sender);

require(claimFrom(runner, msg.sender) > 0, 'RD007');
}

/**
* @notice Claculate the Rewards for user and tranfrer token to user.
*/
function claimFrom(address runner, address user) public returns (uint256) {
_requireNotBlacklisted(settings, msg.sender);
_requireNotBlacklisted(settings, user);

require(
!(IEraManager(settings.getContractAddress(SQContracts.EraManager)).maintenance()),
'G019'
Expand All @@ -451,6 +467,10 @@ contract RewardsDistributor is IRewardsDistributor, Initializable, OwnableUpgrad
}

function claimForDelegate(address runner, address user) public returns (uint256) {
_requireNotBlacklisted(settings, msg.sender);
_requireNotBlacklisted(settings, user);
_requireNotBlacklisted(settings, runner);

require(
!(IEraManager(settings.getContractAddress(SQContracts.EraManager)).maintenance()),
'G019'
Expand Down
10 changes: 10 additions & 0 deletions contracts/RewardsPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ contract RewardsPool is IRewardsPool, Initializable, OwnableUpgradeable, SQParam
* @param amount the labor of services
*/
function labor(bytes32 deploymentId, address runner, uint256 amount) external {
_requireNotBlacklisted(settings, runner);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Blacklist enforcement is incomplete: caller bypass remains possible.

These paths only gate runner; they do not gate msg.sender. A blacklisted account can still interact by calling with a non-blacklisted runner.

Suggested patch
 function labor(bytes32 deploymentId, address runner, uint256 amount) external {
+    _requireNotBlacklisted(settings, msg.sender);
     _requireNotBlacklisted(settings, runner);
     ...
 }

 function collect(bytes32 deploymentId, address runner) external {
+    _requireNotBlacklisted(settings, msg.sender);
     _requireNotBlacklisted(settings, runner);
     ...
 }

 function batchCollect(address runner) external {
+    _requireNotBlacklisted(settings, msg.sender);
     _requireNotBlacklisted(settings, runner);
     ...
 }

 function collectEra(uint256 era, bytes32 deploymentId, address runner) external {
+    _requireNotBlacklisted(settings, msg.sender);
     _requireNotBlacklisted(settings, runner);
     ...
 }

 function batchCollectEra(uint256 era, address runner) external {
+    _requireNotBlacklisted(settings, msg.sender);
     _requireNotBlacklisted(settings, runner);
     ...
 }

Also applies to: 215-215, 227-227, 241-241, 255-255

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@contracts/RewardsPool.sol` at line 153, The blacklist checks currently call
_requireNotBlacklisted(settings, runner) but do not block a blacklisted
msg.sender from delegating through a non-blacklisted runner; update each
occurrence (including the instances at the same pattern around lines ~153, 215,
227, 241, 255) to enforce the blacklist for both parties by calling
_requireNotBlacklisted(settings, msg.sender) in addition to
_requireNotBlacklisted(settings, runner) (or replace with a new helper that
validates both addresses) so that both the caller (msg.sender) and the runner
are checked before proceeding.


require(amount > 0, 'RP002');
IERC20(settings.getContractAddress(SQContracts.SQToken)).safeTransferFrom(
msg.sender,
Expand Down Expand Up @@ -210,6 +212,8 @@ contract RewardsPool is IRewardsPool, Initializable, OwnableUpgradeable, SQParam
* @param runner runner address
*/
function collect(bytes32 deploymentId, address runner) external {
_requireNotBlacklisted(settings, runner);

uint256 currentEra = IEraManager(settings.getContractAddress(SQContracts.EraManager))
.safeUpdateAndGetEra();
_collect(currentEra - 1, deploymentId, runner);
Expand All @@ -220,6 +224,8 @@ contract RewardsPool is IRewardsPool, Initializable, OwnableUpgradeable, SQParam
* @param runner runner address
*/
function batchCollect(address runner) external {
_requireNotBlacklisted(settings, runner);

uint256 currentEra = IEraManager(settings.getContractAddress(SQContracts.EraManager))
.safeUpdateAndGetEra();
_batchCollect(currentEra - 1, runner);
Expand All @@ -232,6 +238,8 @@ contract RewardsPool is IRewardsPool, Initializable, OwnableUpgradeable, SQParam
* @param runner runner address
*/
function collectEra(uint256 era, bytes32 deploymentId, address runner) external {
_requireNotBlacklisted(settings, runner);

uint256 currentEra = IEraManager(settings.getContractAddress(SQContracts.EraManager))
.safeUpdateAndGetEra();
require(currentEra > era, 'RP004');
Expand All @@ -244,6 +252,8 @@ contract RewardsPool is IRewardsPool, Initializable, OwnableUpgradeable, SQParam
* @param runner runner address
*/
function batchCollectEra(uint256 era, address runner) external {
_requireNotBlacklisted(settings, runner);

uint256 currentEra = IEraManager(settings.getContractAddress(SQContracts.EraManager))
.safeUpdateAndGetEra();
require(currentEra > era, 'RP004');
Expand Down
17 changes: 16 additions & 1 deletion contracts/RewardsStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import './interfaces/IStakingAllocation.sol';
import './interfaces/IIndexerRegistry.sol';
import './Constants.sol';
import './utils/MathUtil.sol';
import './utils/SQParameter.sol';

/**
* @title Rewards Staking Contract
Expand All @@ -39,7 +40,7 @@ import './utils/MathUtil.sol';
* 2. These management functions are permissionless, so delegators can call them on runner's behalf so they can remove their delegation from the runner.
*
*/
contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable, SQParameter {
using SafeERC20 for IERC20;
using MathUtil for uint256;

Expand Down Expand Up @@ -144,6 +145,9 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
* Last era's reward need to be collected before this can pass.
*/
function onStakeChange(address _runner, address _source) external onlyStaking {
_requireNotBlacklisted(settings, _runner);
_requireNotBlacklisted(settings, _source);

uint256 currentEra = _getCurrentEra();
uint256 lastEra = currentEra - 1;

Expand Down Expand Up @@ -228,6 +232,8 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
* Last era's reward need to be collected before this can pass.
*/
function onICRChange(address runner, uint256 startEra) external onlyIndexerRegistry {
_requireNotBlacklisted(settings, runner);

uint256 currentEra = _getCurrentEra();
require(startEra > currentEra, 'RS004');

Expand All @@ -246,6 +252,8 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
* @dev Apply the stake change and calaulate the new rewardDebt for staker.
*/
function applyStakeChange(address runner, address staker) external {
_requireNotBlacklisted(settings, staker);

Comment on lines 254 to +256
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Also blacklist-gate runner in applyStakeChange().

This path still settles runner state (getRewardInfo(runner), claimFrom(runner, staker), _updateTotalStakingAmount(..., runner, ...), onStakeUpdate(runner)), but only staker is checked. A runner blacklisted after queuing a stake change can still have rewards/stake state progressed by any caller.

Suggested fix
 function applyStakeChange(address runner, address staker) external {
+        _requireNotBlacklisted(settings, runner);
         _requireNotBlacklisted(settings, staker);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@contracts/RewardsStaking.sol` around lines 254 - 256, The applyStakeChange
function currently only calls _requireNotBlacklisted for staker but proceeds to
modify runner state (getRewardInfo, claimFrom, _updateTotalStakingAmount,
onStakeUpdate); add a blacklist gate for runner by calling
_requireNotBlacklisted(settings, runner) at the start of applyStakeChange
(before any calls to getRewardInfo, claimFrom, _updateTotalStakingAmount, or
onStakeUpdate) so blacklisted runners cannot have their reward/stake state
progressed by this path.

IRewardsDistributor rewardsDistributor = _getRewardsDistributor();
IndexerRewardInfo memory rewardInfo = rewardsDistributor.getRewardInfo(runner);
uint256 lastClaimEra = rewardInfo.lastClaimEra;
Expand Down Expand Up @@ -294,6 +302,9 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
}

function applyRedelegation(address runner, address staker) external onlyStakingManager {
_requireNotBlacklisted(settings, runner);
_requireNotBlacklisted(settings, staker);

IRewardsDistributor rewardsDistributor = _getRewardsDistributor();
IndexerRewardInfo memory rewardInfo = rewardsDistributor.getRewardInfo(runner);
uint256 currentEra = _getCurrentEra();
Expand Down Expand Up @@ -338,6 +349,8 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
* @dev Apply the CommissionRate change and update the commissionRates stored in contract states.
*/
function applyICRChange(address runner) external {
_requireNotBlacklisted(settings, runner);

uint256 currentEra = _getCurrentEra();
require(
pendingCommissionRateChange[runner] != 0 &&
Expand Down Expand Up @@ -397,6 +410,8 @@ contract RewardsStaking is IRewardsStaking, Initializable, OwnableUpgradeable {
* Require to be true when someone try to claimRewards() or onStakeChangeRequested().
*/
function applyRunnerWeightChange(address _runner) public {
_requireNotBlacklisted(settings, _runner);

uint256 _runnerStakeWeight = runnerStakeWeight();
uint256 _previousRunnerStakeWeight = previousRunnerStakeWeight(_runner);
if (_runnerStakeWeight != _previousRunnerStakeWeight) {
Expand Down
27 changes: 25 additions & 2 deletions contracts/Settings.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,46 @@ import './interfaces/ISettings.sol';

contract Settings is ISettings, Initializable, OwnableUpgradeable {
mapping(SQContracts => address) public contractAddresses;
mapping(address => bool) private walletBlacklist;

function initialize() external initializer {
__Ownable_init();
}

function setContractAddress(SQContracts sq, address _address) public {
function setContractAddress(SQContracts sq, address _address) public onlyOwner {
contractAddresses[sq] = _address;
}

function getContractAddress(SQContracts sq) public view returns (address) {
return contractAddresses[sq];
}

function setBatchAddress(SQContracts[] calldata _sq, address[] calldata _address) external {
function setBatchAddress(
SQContracts[] calldata _sq,
address[] calldata _address
) external onlyOwner {
require(_sq.length == _address.length, 'ST001');
for (uint256 i = 0; i < _sq.length; i++) {
contractAddresses[_sq[i]] = _address[i];
}
}

function setWalletBlacklisted(address wallet, bool blacklisted) external onlyOwner {
walletBlacklist[wallet] = blacklisted;
emit WalletBlacklistUpdated(wallet, blacklisted);
}

function setWalletBlacklistedBatch(
address[] calldata wallets,
bool blacklisted
) external onlyOwner {
for (uint256 i = 0; i < wallets.length; i++) {
walletBlacklist[wallets[i]] = blacklisted;
emit WalletBlacklistUpdated(wallets[i], blacklisted);
}
}

function isWalletBlacklisted(address wallet) external view returns (bool) {
return walletBlacklist[wallet];
}
}
Loading
Loading