diff --git a/contracts/ConsumerHost.sol b/contracts/ConsumerHost.sol index f8c3196a..7fa1172a 100644 --- a/contracts/ConsumerHost.sol +++ b/contracts/ConsumerHost.sol @@ -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); @@ -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]; @@ -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' @@ -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' @@ -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' @@ -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' @@ -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' @@ -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 { @@ -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; @@ -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; } diff --git a/contracts/RewardsBooster.sol b/contracts/RewardsBooster.sol index bf5b2bca..a72922a2 100644 --- a/contracts/RewardsBooster.sol +++ b/contracts/RewardsBooster.sol @@ -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) @@ -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); @@ -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( @@ -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 @@ -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) ); @@ -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); diff --git a/contracts/RewardsDistributor.sol b/contracts/RewardsDistributor.sol index 9a6b6f99..a0bcd11c 100644 --- a/contracts/RewardsDistributor.sol +++ b/contracts/RewardsDistributor.sol @@ -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; @@ -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( @@ -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); + // check current era is after lastClaimEra uint256 currentEra = _getCurrentEra(); require(info[runner].lastClaimEra < currentEra - 1, 'RD003'); @@ -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 @@ -429,6 +440,8 @@ 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'); } @@ -436,6 +449,9 @@ contract RewardsDistributor is IRewardsDistributor, Initializable, OwnableUpgrad * @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' @@ -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' diff --git a/contracts/RewardsPool.sol b/contracts/RewardsPool.sol index b55b060b..615c63d4 100644 --- a/contracts/RewardsPool.sol +++ b/contracts/RewardsPool.sol @@ -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); + require(amount > 0, 'RP002'); IERC20(settings.getContractAddress(SQContracts.SQToken)).safeTransferFrom( msg.sender, @@ -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); @@ -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); @@ -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'); @@ -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'); diff --git a/contracts/RewardsStaking.sol b/contracts/RewardsStaking.sol index aadcb9b1..01db0b72 100644 --- a/contracts/RewardsStaking.sol +++ b/contracts/RewardsStaking.sol @@ -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 @@ -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; @@ -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; @@ -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'); @@ -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); + IRewardsDistributor rewardsDistributor = _getRewardsDistributor(); IndexerRewardInfo memory rewardInfo = rewardsDistributor.getRewardInfo(runner); uint256 lastClaimEra = rewardInfo.lastClaimEra; @@ -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(); @@ -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 && @@ -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) { diff --git a/contracts/Settings.sol b/contracts/Settings.sol index b93cbad1..a5707ebc 100644 --- a/contracts/Settings.sol +++ b/contracts/Settings.sol @@ -9,12 +9,13 @@ 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; } @@ -22,10 +23,32 @@ contract Settings is ISettings, Initializable, OwnableUpgradeable { 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]; + } } diff --git a/contracts/Staking.sol b/contracts/Staking.sol index c41f838b..2844e05c 100644 --- a/contracts/Staking.sol +++ b/contracts/Staking.sol @@ -273,6 +273,8 @@ contract Staking is IStaking, Initializable, OwnableUpgradeable, SQParameter { } function addRunner(address _runner) external onlyStakingManager { + _requireNotBlacklisted(settings, _runner); + indexers[indexerLength] = _runner; indexerNo[_runner] = indexerLength; indexerLength++; @@ -323,6 +325,9 @@ contract Staking is IStaking, Initializable, OwnableUpgradeable, SQParameter { uint256 _amount, bool instant ) external { + _requireNotBlacklisted(settings, _source); + _requireNotBlacklisted(settings, _runner); + require( msg.sender == settings.getContractAddress(SQContracts.StakingManager) || msg.sender == address(this), @@ -370,6 +375,8 @@ contract Staking is IStaking, Initializable, OwnableUpgradeable, SQParameter { address _source, uint256 _amount ) external onlyStakingManager { + _requireNotBlacklisted(settings, _source); + IERC20(settings.getContractAddress(SQContracts.SQToken)).safeTransferFrom( _source, address(this), @@ -378,6 +385,8 @@ contract Staking is IStaking, Initializable, OwnableUpgradeable, SQParameter { } function removeDelegation(address _source, address _runner, uint256 _amount) external { + _requireNotBlacklisted(settings, _source); + require( msg.sender == settings.getContractAddress(SQContracts.StakingManager) || msg.sender == address(this), @@ -412,6 +421,8 @@ contract Staking is IStaking, Initializable, OwnableUpgradeable, SQParameter { uint256 _amount, UnbondType _type ) external { + _requireNotBlacklisted(settings, _source); + require( msg.sender == settings.getContractAddress(SQContracts.StakingManager) || msg.sender == address(this), @@ -446,7 +457,10 @@ contract Staking is IStaking, Initializable, OwnableUpgradeable, SQParameter { * burn the withdrawn fees and transfer the rest to delegator. */ function withdrawARequest(address _source, uint256 _index) external onlyStakingManager { + _requireNotBlacklisted(settings, _source); + require(_index == withdrawnLength[_source], 'S009'); + require(block.timestamp >= unbondingAmount[_source][_index].startTime + lockPeriod, 'S016'); withdrawnLength[_source]++; uint256 amount = unbondingAmount[_source][_index].amount; @@ -493,6 +507,8 @@ contract Staking is IStaking, Initializable, OwnableUpgradeable, SQParameter { totalStakingAmount[_runner].valueAfter -= amount; } + lockedAmount[_runner] -= _amount; + IERC20(settings.getContractAddress(SQContracts.SQToken)).safeTransfer( settings.getContractAddress(SQContracts.DisputeManager), _amount @@ -501,6 +517,8 @@ contract Staking is IStaking, Initializable, OwnableUpgradeable, SQParameter { function unbondCommission(address _runner, uint256 _amount) external { require(msg.sender == settings.getContractAddress(SQContracts.RewardsDistributor), 'G003'); + _requireNotBlacklisted(settings, _runner); + lockedAmount[_runner] += _amount; this.startUnbond(_runner, _runner, _amount, UnbondType.Commission); } diff --git a/contracts/StakingAllocation.sol b/contracts/StakingAllocation.sol index 3fcc8900..46a2d4f8 100644 --- a/contracts/StakingAllocation.sol +++ b/contracts/StakingAllocation.sol @@ -17,6 +17,7 @@ import './interfaces/IIndexerRegistry.sol'; import './interfaces/IProjectRegistry.sol'; import './Constants.sol'; import './utils/MathUtil.sol'; +import './utils/SQParameter.sol'; /** * @title Staking Allocation Contract @@ -30,7 +31,7 @@ import './utils/MathUtil.sol'; * Accumulated over allocation time is also tracked in this contract. How much of it will affect the allocation rewards is * further tracked and calculated from RewardsBooster contract, with an additional storage per deployment */ -contract StakingAllocation is IStakingAllocation, Initializable, OwnableUpgradeable { +contract StakingAllocation is IStakingAllocation, Initializable, OwnableUpgradeable, SQParameter { using SafeERC20 for IERC20; using MathUtil for uint256; @@ -75,6 +76,8 @@ contract StakingAllocation is IStakingAllocation, Initializable, OwnableUpgradea */ function onStakeUpdate(address _runner) external { require(msg.sender == settings.getContractAddress(SQContracts.RewardsStaking), 'SAL01'); + _requireNotBlacklisted(settings, _runner); + RunnerAllocation storage ia = _runnerAllocations[_runner]; ia.total = IStakingManager(settings.getContractAddress(SQContracts.StakingManager)) .getEffectiveTotalStake(_runner); @@ -91,6 +94,9 @@ contract StakingAllocation is IStakingAllocation, Initializable, OwnableUpgradea } function addAllocation(bytes32 _deployment, address _runner, uint256 _amount) external { + _requireNotBlacklisted(settings, msg.sender); + _requireNotBlacklisted(settings, _runner); + require(_isAuth(_runner), 'SAL02'); require( IProjectRegistry(settings.getContractAddress(SQContracts.ProjectRegistry)) @@ -105,6 +111,9 @@ contract StakingAllocation is IStakingAllocation, Initializable, OwnableUpgradea } function removeAllocation(bytes32 _deployment, address _runner, uint256 _amount) external { + _requireNotBlacklisted(settings, msg.sender); + _requireNotBlacklisted(settings, _runner); + require(_isAuth(_runner), 'SAL02'); require(allocatedTokens[_runner][_deployment] >= _amount, 'SAL04'); @@ -117,6 +126,9 @@ contract StakingAllocation is IStakingAllocation, Initializable, OwnableUpgradea address _runner, uint256 _amount ) external { + _requireNotBlacklisted(settings, msg.sender); + _requireNotBlacklisted(settings, _runner); + require(_isAuth(_runner), 'SAL02'); require(allocatedTokens[_runner][_deploymentFrom] >= _amount, 'SAL04'); require(_deploymentFrom != _deploymentTo, 'SAL07'); @@ -129,6 +141,8 @@ contract StakingAllocation is IStakingAllocation, Initializable, OwnableUpgradea function stopService(bytes32 _deployment, address _runner) external { require(msg.sender == settings.getContractAddress(SQContracts.ProjectRegistry), 'SAL06'); + _requireNotBlacklisted(settings, _runner); + uint256 amount = allocatedTokens[_runner][_deployment]; if (amount > 0) { diff --git a/contracts/StakingManager.sol b/contracts/StakingManager.sol index 8f954fe0..b4f25085 100644 --- a/contracts/StakingManager.sol +++ b/contracts/StakingManager.sol @@ -11,6 +11,7 @@ import './interfaces/IIndexerRegistry.sol'; import './interfaces/IStakingManager.sol'; import './utils/MathUtil.sol'; import './utils/StakingUtil.sol'; +import './utils/SQParameter.sol'; import './Constants.sol'; import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; @@ -18,7 +19,7 @@ import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; /** * Split from Staking, to keep contract size under control */ -contract StakingManager is IStakingManager, Initializable, OwnableUpgradeable { +contract StakingManager is IStakingManager, Initializable, OwnableUpgradeable, SQParameter { using MathUtil for uint256; ISettings public settings; @@ -46,6 +47,8 @@ contract StakingManager is IStakingManager, Initializable, OwnableUpgradeable { * The caller can be either an existing indexer or IndexerRegistry contract. The staking change will be applied immediately if the caller is IndexerRegistry. */ function stake(address _runner, uint256 _amount) external override { + _requireNotBlacklisted(settings, _runner); + Staking staking = Staking(settings.getContractAddress(SQContracts.Staking)); if (staking.isEmptyDelegation(_runner, _runner)) { require(msg.sender == settings.getContractAddress(SQContracts.IndexerRegistry), 'G001'); @@ -62,6 +65,9 @@ contract StakingManager is IStakingManager, Initializable, OwnableUpgradeable { * Supports instant delegation with quota-based limits and era window restrictions. */ function delegate(address _runner, uint256 _amount) external { + _requireNotBlacklisted(settings, msg.sender); + _requireNotBlacklisted(settings, _runner); + require(msg.sender != _runner, 'G004'); Staking staking = Staking(settings.getContractAddress(SQContracts.Staking)); @@ -114,6 +120,8 @@ contract StakingManager is IStakingManager, Initializable, OwnableUpgradeable { * If the caller is from IndexerRegistry, this function will unstake all the staking token for the indexer. */ function unstake(address _runner, uint256 _amount) external { + _requireNotBlacklisted(settings, _runner); + Staking staking = Staking(settings.getContractAddress(SQContracts.Staking)); if (msg.sender == settings.getContractAddress(SQContracts.IndexerRegistry)) { staking.removeRunner(_runner); @@ -136,6 +144,8 @@ contract StakingManager is IStakingManager, Initializable, OwnableUpgradeable { * @dev Request a unbond from an indexer for specific amount. */ function undelegate(address _runner, uint256 _amount) external { + _requireNotBlacklisted(settings, msg.sender); + // check if called by an indexer require(_runner != msg.sender, 'G004'); Staking staking = Staking(settings.getContractAddress(SQContracts.Staking)); @@ -147,6 +157,9 @@ contract StakingManager is IStakingManager, Initializable, OwnableUpgradeable { * Indexer's self delegations are not allow to redelegate. */ function redelegate(address _fromRunner, address _toRunner, uint256 _amount) external { + _requireNotBlacklisted(settings, msg.sender); + _requireNotBlacklisted(settings, _toRunner); + Staking staking = Staking(settings.getContractAddress(SQContracts.Staking)); address _source = msg.sender; require(_fromRunner != msg.sender, 'G004'); @@ -163,12 +176,18 @@ contract StakingManager is IStakingManager, Initializable, OwnableUpgradeable { // can not be called when the node operator is unregistered // @param _runner the node operator address function stakeReward(address _runner) external { + _requireNotBlacklisted(settings, msg.sender); + _requireNotBlacklisted(settings, _runner); + _stakeReward(msg.sender, _runner, false); } // @dev batch version of stakeReward function batchStakeReward(address[] calldata _runners) external { + _requireNotBlacklisted(settings, msg.sender); + for (uint256 i = 0; i < _runners.length; i++) { + _requireNotBlacklisted(settings, _runners[i]); _stakeReward(msg.sender, _runners[i], true); } } @@ -197,6 +216,8 @@ contract StakingManager is IStakingManager, Initializable, OwnableUpgradeable { } function cancelUnbonding(uint256 unbondReqId) external { + _requireNotBlacklisted(settings, msg.sender); + require( !(IEraManager(settings.getContractAddress(SQContracts.EraManager)).maintenance()), 'G019' @@ -220,6 +241,8 @@ contract StakingManager is IStakingManager, Initializable, OwnableUpgradeable { * Each withdraw need to exceed lockPeriod. */ function widthdraw() external { + _requireNotBlacklisted(settings, msg.sender); + require( !(IEraManager(settings.getContractAddress(SQContracts.EraManager)).maintenance()), 'G019' diff --git a/contracts/StateChannel.sol b/contracts/StateChannel.sol index eb232ab3..7764ead8 100644 --- a/contracts/StateChannel.sol +++ b/contracts/StateChannel.sol @@ -191,6 +191,10 @@ contract StateChannel is Initializable, OwnableUpgradeable, SQParameter { bytes memory indexerSign, bytes memory consumerSign ) external { + _requireNotBlacklisted(settings, msg.sender); + _requireNotBlacklisted(settings, indexer); + _requireNotBlacklisted(settings, consumer); + // check channel exist require(channels[channelId].status == ChannelStatus.Finalized, 'SC001'); @@ -274,6 +278,9 @@ contract StateChannel is Initializable, OwnableUpgradeable, SQParameter { bytes memory consumerSign, uint256 price ) external { + _requireNotBlacklisted(settings, msg.sender); + _requireChannelWalletsNotBlacklisted(channelId); + address indexer = channels[channelId].indexer; address consumer = channels[channelId].consumer; require(channels[channelId].expiredAt == preExpirationAt, 'SC002'); @@ -310,6 +317,9 @@ contract StateChannel is Initializable, OwnableUpgradeable, SQParameter { bytes memory callback, bytes memory sign ) external { + _requireNotBlacklisted(settings, msg.sender); + _requireChannelWalletsNotBlacklisted(channelId); + require(channels[channelId].status == ChannelStatus.Open, 'SC003'); require(channels[channelId].total == preTotal, 'SC010'); @@ -336,6 +346,9 @@ contract StateChannel is Initializable, OwnableUpgradeable, SQParameter { * @param query the state of the channel */ function checkpoint(QueryState calldata query) external { + _requireNotBlacklisted(settings, msg.sender); + _requireChannelWalletsNotBlacklisted(query.channelId); + // check channel status require(channels[query.channelId].status == ChannelStatus.Open, 'SC004'); @@ -360,6 +373,9 @@ contract StateChannel is Initializable, OwnableUpgradeable, SQParameter { * @param query the state of the channel */ function terminate(QueryState calldata query) external { + _requireNotBlacklisted(settings, msg.sender); + _requireChannelWalletsNotBlacklisted(query.channelId); + ChannelState storage state = channels[query.channelId]; // check sender @@ -400,6 +416,9 @@ contract StateChannel is Initializable, OwnableUpgradeable, SQParameter { } function terminateWithCurrentState(uint256 channelId) external { + _requireNotBlacklisted(settings, msg.sender); + _requireChannelWalletsNotBlacklisted(channelId); + ChannelState storage state = channels[channelId]; // check sender @@ -433,6 +452,9 @@ contract StateChannel is Initializable, OwnableUpgradeable, SQParameter { * @param query the state of the channel */ function respond(QueryState calldata query) external { + _requireNotBlacklisted(settings, msg.sender); + _requireChannelWalletsNotBlacklisted(query.channelId); + ChannelState storage state = channels[query.channelId]; // check state and sender @@ -463,6 +485,9 @@ contract StateChannel is Initializable, OwnableUpgradeable, SQParameter { * @param channelId channel id */ function claim(uint256 channelId) external { + _requireNotBlacklisted(settings, msg.sender); + _requireChannelWalletsNotBlacklisted(channelId); + // check if terminate success bool isClaimable1 = channels[channelId].status == ChannelStatus.Terminating && channels[channelId].terminatedAt < block.timestamp; @@ -595,6 +620,7 @@ contract StateChannel is Initializable, OwnableUpgradeable, SQParameter { uint256 rewardsAmount = IRewardsBooster(rbAddress).spendQueryRewards( channels[channelId].deploymentId, realConsumer, + channels[channelId].indexer, spent - rewardsTotal, abi.encode(channelId) ); @@ -657,6 +683,7 @@ contract StateChannel is Initializable, OwnableUpgradeable, SQParameter { if (isCConsumer) { IConsumer cConsumer = IConsumer(consumer); (realConsumer, ) = cConsumer.decodeConsumerCallback(callback); + _requireNotBlacklisted(settings, realConsumer); if (cConsumer.channelConsumer(channelId) == address(0)) { cConsumer.setChannelConsumer(channelId, callback); } @@ -664,7 +691,13 @@ contract StateChannel is Initializable, OwnableUpgradeable, SQParameter { // transfer the rewards to channel uint256 fundByReward = IRewardsBooster( settings.getContractAddress(SQContracts.RewardsBooster) - ).spendQueryRewards(deploymentId, realConsumer, amount, abi.encode(channelId)); + ).spendQueryRewards( + deploymentId, + realConsumer, + channels[channelId].indexer, + amount, + abi.encode(channelId) + ); uint256 realAmount = 0; if (fundByReward < amount) { realAmount = amount - fundByReward; @@ -684,6 +717,11 @@ contract StateChannel is Initializable, OwnableUpgradeable, SQParameter { emit ChannelFund(channelId, channels[channelId].realTotal, channels[channelId].total); } + function _requireChannelWalletsNotBlacklisted(uint256 channelId) private view { + _requireNotBlacklisted(settings, channels[channelId].indexer); + _requireNotBlacklisted(settings, channels[channelId].consumer); + } + /// @dev check if consumer is valid contract consumer /// @return false if it is not a contract /// true if it is a contract and implements IConsumer interface and in the whitelist diff --git a/contracts/interfaces/IRewardsBooster.sol b/contracts/interfaces/IRewardsBooster.sol index e1adba8c..2b548185 100644 --- a/contracts/interfaces/IRewardsBooster.sol +++ b/contracts/interfaces/IRewardsBooster.sol @@ -50,6 +50,7 @@ interface IRewardsBooster { function spendQueryRewards( bytes32 _deploymentId, address _spender, + address _runner, uint256 _amount, bytes calldata data ) external returns (uint256); diff --git a/contracts/interfaces/ISettings.sol b/contracts/interfaces/ISettings.sol index b5c9a9a3..ee91141c 100644 --- a/contracts/interfaces/ISettings.sol +++ b/contracts/interfaces/ISettings.sol @@ -28,9 +28,17 @@ enum SQContracts { } interface ISettings { + event WalletBlacklistUpdated(address indexed wallet, bool blacklisted); + function setBatchAddress(SQContracts[] calldata sq, address[] calldata _address) external; function setContractAddress(SQContracts sq, address _address) external; function getContractAddress(SQContracts sq) external view returns (address); + + function setWalletBlacklisted(address wallet, bool blacklisted) external; + + function setWalletBlacklistedBatch(address[] calldata wallets, bool blacklisted) external; + + function isWalletBlacklisted(address wallet) external view returns (bool); } diff --git a/contracts/utils/SQParameter.sol b/contracts/utils/SQParameter.sol index 14ac32ff..a5be5b94 100644 --- a/contracts/utils/SQParameter.sol +++ b/contracts/utils/SQParameter.sol @@ -3,7 +3,15 @@ pragma solidity ^0.8.15; +import '../interfaces/ISettings.sol'; + abstract contract SQParameter { /// @notice Emitted when parameter change. event Parameter(string name, bytes value); + + function _requireNotBlacklisted(ISettings settings, address wallet) internal view { + if (settings.isWalletBlacklisted(wallet)) { + revert(); + } + } } diff --git a/publish/ABI/RewardsBooster.json b/publish/ABI/RewardsBooster.json index cc9470fe..31169291 100644 --- a/publish/ABI/RewardsBooster.json +++ b/publish/ABI/RewardsBooster.json @@ -358,6 +358,29 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_deploymentId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "_account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "adminRemoveBoosterDeployment", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1363,6 +1386,11 @@ "name": "_spender", "type": "address" }, + { + "internalType": "address", + "name": "_runner", + "type": "address" + }, { "internalType": "uint256", "name": "_amount", diff --git a/publish/ABI/RewardsStaking.json b/publish/ABI/RewardsStaking.json index 4700d644..a5451fb6 100644 --- a/publish/ABI/RewardsStaking.json +++ b/publish/ABI/RewardsStaking.json @@ -50,6 +50,25 @@ "name": "OwnershipTransferred", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "value", + "type": "bytes" + } + ], + "name": "Parameter", + "type": "event" + }, { "anonymous": false, "inputs": [ diff --git a/publish/ABI/Settings.json b/publish/ABI/Settings.json index cc575eb7..6f36e85f 100644 --- a/publish/ABI/Settings.json +++ b/publish/ABI/Settings.json @@ -31,6 +31,25 @@ "name": "OwnershipTransferred", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "wallet", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "blacklisted", + "type": "bool" + } + ], + "name": "WalletBlacklistUpdated", + "type": "event" + }, { "inputs": [ { @@ -76,6 +95,25 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "wallet", + "type": "address" + } + ], + "name": "isWalletBlacklisted", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "owner", @@ -132,6 +170,42 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "wallet", + "type": "address" + }, + { + "internalType": "bool", + "name": "blacklisted", + "type": "bool" + } + ], + "name": "setWalletBlacklisted", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "wallets", + "type": "address[]" + }, + { + "internalType": "bool", + "name": "blacklisted", + "type": "bool" + } + ], + "name": "setWalletBlacklistedBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/publish/ABI/StakingAllocation.json b/publish/ABI/StakingAllocation.json index 60c9c3ee..e3ca11aa 100644 --- a/publish/ABI/StakingAllocation.json +++ b/publish/ABI/StakingAllocation.json @@ -75,6 +75,25 @@ "name": "OwnershipTransferred", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "value", + "type": "bytes" + } + ], + "name": "Parameter", + "type": "event" + }, { "anonymous": false, "inputs": [ diff --git a/publish/ABI/StakingManager.json b/publish/ABI/StakingManager.json index 63caef3b..f56fcd4d 100644 --- a/publish/ABI/StakingManager.json +++ b/publish/ABI/StakingManager.json @@ -31,6 +31,25 @@ "name": "OwnershipTransferred", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "value", + "type": "bytes" + } + ], + "name": "Parameter", + "type": "event" + }, { "inputs": [ { diff --git a/publish/mainnet.json b/publish/mainnet.json index 9d156e89..b7c11733 100644 --- a/publish/mainnet.json +++ b/publish/mainnet.json @@ -7,10 +7,10 @@ "lastUpdate": "Tue, 13 Feb 2024 08:03:25 GMT" }, "Settings": { - "innerAddress": "0xB7a3A05b07b1B456b3c28d0d985d85bf9F61A698", + "innerAddress": "0x19416C46e6eb5882e3F4C7AD367D79140aD48E1F", "address": "0xB05E83a560f84aF90622909FE7190cE538CC3566", - "bytecodeHash": "b1739cec229c357424af68e741fc1c7e0204b758a5dd2cb4f24c6ba022127eec", - "lastUpdate": "Tue, 13 Feb 2024 08:06:29 GMT" + "bytecodeHash": "6870f38bb1c63cf0a51cfb82351ea11a602486c0e3cba7979de12fe169d6ce01", + "lastUpdate": "Mon, 13 Apr 2026 03:24:03 GMT" }, "SQToken": { "innerAddress": "", @@ -63,10 +63,10 @@ "lastUpdate": "Wed, 28 Feb 2024 03:56:57 GMT" }, "Settings": { - "innerAddress": "0xf282737992Da4217bf5f8B6AE621181e84d7d3b9", + "innerAddress": "0x9dDB88d712FE6aA5260a53Eb42CdC0F0b6F7a6fa", "address": "0x1d1e8C85A2C99575fCb95903C9aD9Ae2aDEA54fc", - "bytecodeHash": "b1739cec229c357424af68e741fc1c7e0204b758a5dd2cb4f24c6ba022127eec", - "lastUpdate": "Tue, 13 Feb 2024 08:43:05 GMT" + "bytecodeHash": "6d16367cd90fae6496e3825e881efc64ba0b08cc2e3d32abb9a95025858c3db0", + "lastUpdate": "Tue, 14 Apr 2026 03:56:13 GMT" }, "L2SQToken": { "innerAddress": "", @@ -81,16 +81,16 @@ "lastUpdate": "Tue, 13 Feb 2024 09:10:08 GMT" }, "Staking": { - "innerAddress": "0xf6C913C506881D7EB37Ce52af4Dc8E59FD61694d", + "innerAddress": "0x27AA37Ad388Ee3F559016aea806C5BCc98E37e70", "address": "0x7A68b10EB116a8b71A9b6f77B32B47EB591B6Ded", - "bytecodeHash": "bb8fbc9eae5a63035103c1a375a90fe249aa0f404598f6bbc00246b362d27655", - "lastUpdate": "Tue, 11 Nov 2025 03:01:21 GMT" + "bytecodeHash": "1fb348297ecc1e94ab8de76be8b97a6624576249cfda70a2450bef06e016af53", + "lastUpdate": "Thu, 23 Apr 2026 01:51:03 GMT" }, "StakingManager": { - "innerAddress": "0xd40cCE79C65a1c08474819a8ceCF6b37CEc8F686", + "innerAddress": "0xD7C2cB905ddee644b96007f3cf2a01cdCb2B36d8", "address": "0x09395a2A58DB45db0da254c7EAa5AC469D8bDc85", - "bytecodeHash": "37edec3315f4dd87c67851de6a149709bf68290a7598154169b5e19872047401", - "lastUpdate": "Tue, 11 Nov 2025 03:01:23 GMT" + "bytecodeHash": "5c5db6e550aca52bf6a21f34e7013b941de53baa4f597b48e787255818ce3bee", + "lastUpdate": "Tue, 14 Apr 2026 03:55:33 GMT" }, "EraManager": { "innerAddress": "0x94A8E45E9D6dCA44A95BEc33E828B9E9257443D6", @@ -135,22 +135,22 @@ "lastUpdate": "Wed, 14 Feb 2024 02:40:50 GMT" }, "RewardsDistributor": { - "innerAddress": "0xc57078d0B1d82C4b365A5f72779F1655f02EAF66", + "innerAddress": "0xfe934bfF662Ce81f93Fed6BB50A81001c471d6d3", "address": "0x18AEC6c407235d446E52Aa243CD1A75421bb264e", - "bytecodeHash": "3ea33c35b751d1b7f0af0fec0a560adc0c2718663bab9dc0570db1d1ea4d13f4", - "lastUpdate": "Wed, 30 Apr 2025 01:54:28 GMT" + "bytecodeHash": "0f35bdfa0e953a87679f98148dd5319b579133cb04784ba3dbd78a4100a9135d", + "lastUpdate": "Tue, 14 Apr 2026 03:54:43 GMT" }, "RewardsPool": { - "innerAddress": "0x7b7aaB2c8759473f5d994F6D633A6427286Ee27d", + "innerAddress": "0x3cbdb0752BF23Be8670f0431A1eA4D929a5Cca26", "address": "0xd2b00e427e3FE06Be815C20039421308f0487d03", - "bytecodeHash": "e84d8610221fe53056325d6e6b819628877a7b1fc12c4cf39c4a315823423604", - "lastUpdate": "Thu, 06 Mar 2025 03:15:22 GMT" + "bytecodeHash": "3a71574730f1d6f0ea7bc7244cd29b9c7e2245f16a2185b79d883e1707c5efaa", + "lastUpdate": "Tue, 14 Apr 2026 03:54:53 GMT" }, "RewardsStaking": { - "innerAddress": "0x9288CFf738337288957BB7f30D8069Bc5496e5e5", + "innerAddress": "0x93e77E02F544b841cA667B495C923CB2195E21Ae", "address": "0x1c285c5513f2135f8AD12A930E6473dA47581BE8", - "bytecodeHash": "b7ea386b1b987be564f8ce09ab9c027393e41b15ee582ef01da7c74170e1fe18", - "lastUpdate": "Wed, 30 Apr 2025 01:54:36 GMT" + "bytecodeHash": "a16a177cda45b7805b111cc1d652606a52fb13798a3d73b9818d7d45e3861a4b", + "lastUpdate": "Tue, 14 Apr 2026 03:55:03 GMT" }, "RewardsHelper": { "innerAddress": "0x6A5E0CDD9695A954B52647145CA98152A1D840e1", @@ -159,16 +159,16 @@ "lastUpdate": "Wed, 14 Feb 2024 02:42:07 GMT" }, "StateChannel": { - "innerAddress": "0x2C493FDc57b0F35839656039c8879b983e1BA35a", + "innerAddress": "0x0C2da86b9f37FE2BbD9D144651175778F73c955E", "address": "0x6797Df373589dF2AA37FA353c4254FD7834B751A", - "bytecodeHash": "bb3d108e42429ce773225191d355ccf0762af6a8fd38301e7ac5f44a6451fd44", - "lastUpdate": "Mon, 12 May 2025 01:52:46 GMT" + "bytecodeHash": "7e47fd4813eefca62751f96df27ebc0b7a04568e75257ab912aa2affe212b4d8", + "lastUpdate": "Tue, 14 Apr 2026 03:55:53 GMT" }, "ConsumerHost": { - "innerAddress": "0xADE7098d9fa3E712e252e4207240e7E2e68811c5", + "innerAddress": "0xe345249d7E67548C911cC5F213348F270E35ecAd", "address": "0x1185FD5a8B1dcdea654790219eAfA87105F201C5", - "bytecodeHash": "16a3a1b83ee23e2822a8db2e7fe955a33e3363fe8cee7b02930f907451f1767c", - "lastUpdate": "Mon, 12 May 2025 01:52:52 GMT" + "bytecodeHash": "4a6faef02932c60ab8b4b8371a3c67ec0c2dc881eb6893cf9e4b541410157995", + "lastUpdate": "Tue, 14 Apr 2026 03:56:03 GMT" }, "DisputeManager": { "innerAddress": "0xbec62e17BBF014c748ce2913f8F4108183566a07", @@ -195,16 +195,16 @@ "lastUpdate": "Tue, 21 May 2024 22:09:56 GMT" }, "RewardsBooster": { - "innerAddress": "0x5391935FF85a062ADF8087E3deeee05e66D4db49", + "innerAddress": "0x90490d4F4D84e903AAEaC8dc7d55e3663A580500", "address": "0x7F138D57A5e05b6FBF3bCAdDa9a1252354245464", - "bytecodeHash": "024bc32b1c971607259b8f89791c5d0c6eb936ea39c5df0924681fc583cae040", - "lastUpdate": "Sat, 31 Jan 2026 06:13:07 GMT" + "bytecodeHash": "54eae3b8a11f395bf40428d3c0c2f0053d5ce3695540b8a5130526040a31ced8", + "lastUpdate": "Tue, 14 Apr 2026 03:55:13 GMT" }, "StakingAllocation": { - "innerAddress": "0xF01E9D5AEC5BE9a149362628cC5B4d20F05473A1", + "innerAddress": "0x901397C3Aa0B2993C9431501dec2B13606d42Eb0", "address": "0x20E4B978b930ce17a499C33BbF958b5b920F70E1", - "bytecodeHash": "5b7a4526cd014752bfb043183847be9fc0e458704e7429e857b5f8c3befeadde", - "lastUpdate": "Sat, 31 Jan 2026 06:13:17 GMT" + "bytecodeHash": "3ce3b37670bb0d5a7ecb7f0b1d93ae9104bd96c337db134ea105348db38dd23c", + "lastUpdate": "Tue, 14 Apr 2026 03:55:43 GMT" }, "Airdropper": { "innerAddress": "0xbdF10CE01BE0d0d51c733800382b7A300f9273e4", diff --git a/test/RewardsBooster.test.ts b/test/RewardsBooster.test.ts index aee2eac3..80ec2b9c 100644 --- a/test/RewardsBooster.test.ts +++ b/test/RewardsBooster.test.ts @@ -17,6 +17,7 @@ import { StakingManager, RewardsDistributor, RewardsStaking, + Settings, } from '../src'; import { deploymentIds, deploymentMetadatas, projectMetadatas } from './constants'; import { @@ -70,6 +71,7 @@ describe('RewardsBooster Contract', () => { let projectRegistry: ProjectRegistry; let stateChannel: StateChannel; let consumerRegistry: ConsumerRegistry; + let settings: Settings; const getAllocationReward = (deploymentReward: BigNumber, queryRewardRatePerMill: BigNumber): BigNumber => { return deploymentReward.mul(PER_MILL.sub(queryRewardRatePerMill)).div(PER_MILL); @@ -142,6 +144,7 @@ describe('RewardsBooster Contract', () => { projectRegistry = deployment.projectRegistry; stateChannel = deployment.stateChannel; consumerRegistry = deployment.consumerRegistry; + settings = deployment.settings; await token.approve(rewardsBooster.address, constants.MaxInt256); // config rewards booster @@ -252,6 +255,21 @@ describe('RewardsBooster Contract', () => { revertMsg.notOwner ); }); + + it('owner can blacklist wallets', async () => { + await expect(settings.connect(runner0).setWalletBlacklisted(consumer0.address, true)).to.be.revertedWith( + revertMsg.notOwner + ); + + await expect(settings.setWalletBlacklisted(consumer0.address, true)) + .to.emit(settings, 'WalletBlacklistUpdated') + .withArgs(consumer0.address, true); + expect(await settings.isWalletBlacklisted(consumer0.address)).to.eq(true); + + await settings.setWalletBlacklistedBatch([consumer0.address, consumer1.address], false); + expect(await settings.isWalletBlacklisted(consumer0.address)).to.eq(false); + expect(await settings.isWalletBlacklisted(consumer1.address)).to.eq(false); + }); }); describe('boost deployments', () => { @@ -278,6 +296,38 @@ describe('RewardsBooster Contract', () => { await rewardsBooster.removeBoosterDeployment(deploymentId0, boosterAmount); expect(await token.balanceOf(root.address)).to.eq(balanceBefore); }); + + it('owner can remove booster accounting without transferring tokens', async () => { + const boosterAmount = etherParse('10000'); + const removeAmount = boosterAmount; + await token.increaseAllowance(rewardsBooster.address, boosterAmount); + await rewardsBooster.boostDeployment(deploymentId0, boosterAmount); + + const ownerBalanceBefore = await token.balanceOf(root.address); + const boosterBalanceBefore = await token.balanceOf(rewardsBooster.address); + + await expect( + rewardsBooster.connect(runner0).adminRemoveBoosterDeployment(deploymentId0, root.address, removeAmount) + ).to.be.revertedWith(revertMsg.notOwner); + + await expect(rewardsBooster.adminRemoveBoosterDeployment(deploymentId0, root.address, removeAmount)) + .to.emit(rewardsBooster, 'DeploymentBoosterRemoved') + .withArgs(deploymentId0, root.address, removeAmount); + + expect(await rewardsBooster.getRunnerDeploymentBooster(deploymentId0, root.address)).to.eq(0); + expect(await token.balanceOf(root.address)).to.eq(ownerBalanceBefore); + expect(await token.balanceOf(rewardsBooster.address)).to.eq(boosterBalanceBefore); + }); + + it('blacklisted wallet can not use RewardsBooster', async () => { + const boosterAmount = etherParse('10000'); + await token.connect(consumer0).increaseAllowance(rewardsBooster.address, boosterAmount); + await settings.setWalletBlacklisted(consumer0.address, true); + + await expect(rewardsBooster.connect(consumer0).boostDeployment(deploymentId0, boosterAmount)).to.be + .reverted; + }); + it('can add and remove booster to a deployment from controller', async () => { const boosterAmount = etherParse('10000'); const balanceBefore = await token.balanceOf(runner0.address); diff --git a/test/RewardsBooster_migration.test.ts b/test/RewardsBooster_migration.test.ts index 4a7a04e1..b38dd48e 100644 --- a/test/RewardsBooster_migration.test.ts +++ b/test/RewardsBooster_migration.test.ts @@ -134,7 +134,7 @@ describe('RewardsBooster Contract', () => { token = deployment.token; eraManager = deployment.eraManager; rewardsBooster = deployment.rewardsBooster; - rewardsBoosterOld = rewardsBoosterOldContract.connect(deployment.rewardsBooster.address); + rewardsBoosterOld = rewardsBoosterOldContract.attach(deployment.rewardsBooster.address); rewardsStaking = deployment.rewardsStaking; rewardsDistributor = deployment.rewardsDistributor; rewardsHelper = deployment.rewardsHelper; @@ -446,8 +446,13 @@ describe('RewardsBooster Contract', () => { expect(deploymentPool0Before.boosterPoint).to.eq(etherParse('40000')); // migrate await upgrade(); - await rewardsBooster.spendQueryRewards(deploymentId0, consumer0.address, etherParse('1'), '0x00'); - // check boost changes + await rewardsBooster.spendQueryRewards( + deploymentId0, + consumer0.address, + runner0.address, + etherParse('1'), + '0x00' + ); const deploymentPool0After = await rewardsBooster.deploymentPools(deploymentId0); const deploymentPoolByType0After = await rewardsBooster.deploymentPoolsByType(deploymentId0); const totalBoostAfter = await rewardsBooster.totalBoosterPoint(); @@ -484,7 +489,7 @@ describe('RewardsBooster Contract', () => { const deploymentPool0Before = await rewardsBooster.deploymentPools(deploymentId0); const totalBoostBefore = await rewardsBooster.totalBoosterPoint(); expect(deploymentPool0Before.boosterPoint).to.eq(etherParse('40000')); - await rewardsBooster.spendQueryRewards(deploymentId0, consumer0.address, etherParse('1'), '0x00'); + await rewardsBoosterOld.spendQueryRewards(deploymentId0, consumer0.address, etherParse('1'), '0x00'); // migrate await upgrade(); await token.increaseAllowance(rewardsBooster.address, etherParse('1')); @@ -526,7 +531,7 @@ describe('RewardsBooster Contract', () => { expect(alReward0).to.gt(0); const deploymentPool0Before = await rewardsBooster.deploymentPools(deploymentId0); expect(deploymentPool0Before.boosterPoint).to.eq(etherParse('40000')); - await rewardsBooster.spendQueryRewards(deploymentId0, consumer0.address, etherParse('1'), '0x00'); + await rewardsBoosterOld.spendQueryRewards(deploymentId0, consumer0.address, etherParse('1'), '0x00'); // migrate await upgrade(); await rewardsBooster.migrateDeploymentBoost(deploymentId0, consumer0.address); @@ -537,13 +542,25 @@ describe('RewardsBooster Contract', () => { ).to.revertedWith('RB007'); await blockTravel(2000); // spend query rewards from old pool - await rewardsBooster.spendQueryRewards(deploymentId0, consumer0.address, existingRewards, '0x00'); + await rewardsBooster.spendQueryRewards( + deploymentId0, + consumer0.address, + runner0.address, + existingRewards, + '0x00' + ); // fail because neither old pool nor new pool has spent >= existingRewards X2 await expect( rewardsBooster.refundQueryRewards(deploymentId0, consumer0.address, existingRewards.mul(2), '0x00') ).to.revertedWith('RB007'); // spend query rewards from new pool - await rewardsBooster.spendQueryRewards(deploymentId0, consumer0.address, existingRewards.mul(2), '0x00'); + await rewardsBooster.spendQueryRewards( + deploymentId0, + consumer0.address, + runner0.address, + existingRewards.mul(2), + '0x00' + ); // refund to new pool // await rewardsBooster.refundQueryRewards(deploymentId0, consumer0.address, existingRewards.mul(2), '0x00'); await expect( @@ -598,6 +615,7 @@ describe('RewardsBooster Contract', () => { const tx = await rewardsBooster.spendQueryRewards( deploymentId0, consumer0.address, + runner0.address, queryReward0After2, '0x00' ); diff --git a/test/RewardsDistributer.test.ts b/test/RewardsDistributer.test.ts index 9389789e..6030332b 100644 --- a/test/RewardsDistributer.test.ts +++ b/test/RewardsDistributer.test.ts @@ -15,6 +15,7 @@ import { RewardsStaking, Staking, StakingManager, + Settings, } from '../src'; import { DEPLOYMENT_ID, METADATA_HASH, VERSION } from './constants'; import { acceptPlan, addInstantRewards, etherParse, eventFrom, startNewEra, time, timeTravel } from './helper'; @@ -33,6 +34,7 @@ describe('RewardsDistributor Contract', () => { let rewardsDistributor: RewardsDistributor; let rewardsStaking: RewardsStaking; let rewardsHelper: RewardsHelper; + let settings: Settings; //rewrite registerIndexer to registe indexer with stakeAmount and commissionRate const registerIndexer = async (rootWallet, wallet, amount, rate) => { @@ -87,6 +89,7 @@ describe('RewardsDistributor Contract', () => { rewardsStaking = deployment.rewardsStaking; rewardsHelper = deployment.rewardsHelper; eraManager = deployment.eraManager; + settings = deployment.settings; //init delegator account await token.connect(root).transfer(delegator.address, etherParse('10')); @@ -636,6 +639,12 @@ describe('RewardsDistributor Contract', () => { await expect(rewardsDistributor.connect(delegator).claim(runner.address)).to.be.revertedWith('RD007'); }); + it('blacklisted wallet can not claim rewards', async () => { + await settings.setWalletBlacklisted(delegator.address, true); + + await expect(rewardsDistributor.connect(delegator).claim(runner.address)).to.be.reverted; + }); + // it('claim each era should get same rewards with claim once', async () => { // //move to Era 3 // await startNewEra(eraManager); diff --git a/test/Staking.test.ts b/test/Staking.test.ts index d4a67574..0bc6697d 100644 --- a/test/Staking.test.ts +++ b/test/Staking.test.ts @@ -15,6 +15,7 @@ import { Staking, StakingManager, RewardsHelper, + Settings, } from '../src'; import { addInstantRewards, @@ -39,6 +40,7 @@ describe('Staking Contract', () => { let rewardsDistributor: RewardsDistributor; let rewardsStaking: RewardsStaking; let rewardsHelper: RewardsHelper; + let settings: Settings; const selfStake = etherParse('2002'); @@ -86,6 +88,7 @@ describe('Staking Contract', () => { rewardsDistributor = deployment.rewardsDistributor; rewardsStaking = deployment.rewardsStaking; rewardsHelper = deployment.rewardsHelper; + settings = deployment.settings; await configWallet(); }); @@ -144,6 +147,12 @@ describe('Staking Contract', () => { ); }); + it('blacklisted wallet can not use staking actions', async () => { + await settings.setWalletBlacklisted(delegator.address, true); + + await expect(stakingManager.connect(delegator).delegate(runner.address, etherParse('1'))).to.be.reverted; + }); + it('unstaking by indexer should work', async () => { const unstakeAmount = etherParse('0.5'); await stakingManager.connect(runner).unstake(runner.address, unstakeAmount);