Smart contracts with functions BlackList
We continue the series of articles devoted to the description of fraudulent schemes in smart contracts. Today we will analyze smart contracts with Black List functions (BlackList).
The dangers of smart contracts with functions BlackList:
Smart contracts that include Blacklist functions carry certain risks and problems for both the project and its users. Here are some of the dangers associated with blacklist functions:
- Centralized Control: Blacklist functions often provide centralized control to the contract owner or administrators.
- Blacklist Abuse for Unfair Practices: Abusers (including the contract owner), may use the blacklist to target specific addresses. This may include freezing or restricting the functionality of accounts without good reason.
- Lack of transparency: The existence of blacklisting functions, especially if they are not documented, can lead to a lack of transparency. Users may not be aware of the blacklisting criteria or the blacklisting procedure.
- Security risks: If BlackList is not implemented securely, there is a risk of vulnerabilities that could allow unauthorized parties to manipulate the blacklist, which could lead to unauthorized freezing or transfer of funds.
- User distrust: The existence of blacklist functions can undermine user trust as their assets can be blacklisted without clear rules.
- Token confiscation: Attackers can use a blacklist to confiscate tokens or assets from certain addresses without proper justification. This can result in significant financial losses.
How can you independently determine if such threats are present in smart contracts?
When validating a smart contract, certain steps can be taken to determine if there is a threat associated with blacklist functions:
- Before you start working with a smart contract, carefully read and study its code, including all functions related to blacklisting. Look for functions related to blacklisting, freezing, or limiting account functionality. Check for functions that allow you to add or remove addresses from the blacklist.
- Analyze who has ownership or administrative control over the contract. Assess the degree of control and rights associated with the owner or administrators.
- Examine the contract documentation to understand how the blacklisting functions are intended to be used. Seek information on the governance mechanisms that control the use of blacklisting.
- Assess transparency: Does the contract ensure that the blacklisting criteria are transparent? Check whether there are clear procedures for eliminating false positives or removing addresses from the blacklist.
- Security audits: check whether the smart contract has undergone security audits by reputable third-party companies.
- Familiarize yourself with feedback from the community or online forums about the use of blacklists in the project. Be alert to any red flags raised by community members about unfair practices or lack of transparency.
- By conducting a thorough analysis and taking the above factors into account, you will be better able to assess the risks associated with blacklist functions in smart contracts. Stay up to date with the latest developments in our community (Telegram channel) and best practices for fraud detection (our Blog and YouTube channel).
Good news: our Security Scanner finds all common (including hidden) Blacklist functions (BlackList) 99.9% of the time. Use our premium subscription and protect your funds from threats.
Next, we will look at a few of the most common examples of BlackList functions that our Platform successfully detects.
Note that these are simplified examples and the actual implementation may differ. When analyzing smart contracts, you should always perform a thorough code review and consider context-dependent factors.
Example 1: Basic functionality of the Black List
contract TokenWithBlackListAndFee {
address public owner;
mapping(address => bool) public BlackList;
uint256 public BlackListFee;
constructor(uint256 _fee) {
owner = msg.sender;
BlackListFee = _fee;
}
modifier onlyOwner() {
require(msg.sender == owner, "Only the owner can modify the BlackList");
_;
}
function addToBlackListWithFee(address _account) public payable onlyOwner {
require(msg.value >= BlackListFee, "Insufficient fee");
BlackList[_account] = true;
}
function removeFromBlackList(address _account) public onlyOwner {
BlackList[_account] = false;
}
}
Detection Tips:Look for functions (such as addToBlackList and removeFromBlackList) that have access modifiers (onlyOwner). The presence of such modifiers means that only the Owner can modify the blacklist.
Example 2: Blacklist with Fee Mechanism (BlackList with Fee)
contract TokenWithBlackListAndFee {
address public owner;
mapping(address => bool) public BlackList;
uint256 public BlackListFee;
constructor(uint256 _fee) {
owner = msg.sender;
BlackListFee = _fee;
}
modifier onlyOwner() {
require(msg.sender == owner, "Only the owner can modify the BlackList");
_;
}
function addToBlackListWithFee(address _account) public payable onlyOwner {
require(msg.value >= BlackListFee, "Insufficient fee");
BlackList[_account] = true;
}
function removeFromBlackList(address _account) public onlyOwner {
BlackList[_account] = false;
}
}
Detection Tips:Define functions (such as addToBlackListWithFee) that require a charge (msg.value) to be blacklisted. This is a very dangerous signal.
Example 3: Blacklist with time-dependent conditions
contract TokenWithTimeLock {
address public owner;
mapping(address => bool) public BlackList;
uint256 public BlackListTimeLock;
constructor(uint256 _timeLock) {
owner = msg.sender;
BlackListTimeLock = _timeLock;
}
modifier onlyOwner() {
require(msg.sender == owner, "Only the owner can modify the BlackList");
_;
}
function addToBlackListTimed(address _account) public onlyOwner {
require(block.timestamp >= BlackListTimeLock, "Time lock not yet expired");
BlackList[_account] = true;
}
function removeFromBlackList(address _account) public onlyOwner {
BlackList[_account] = false;
}
}
Detection Tips:Define functions (e.g. addToBlackListTimed) that impose block time dependent conditions on the blacklist. This is typically used for delayed or scheduled blacklists.
Example 4: Blacklist with Events logging
contract TokenWithBlackListAndEvents {
address public owner;
mapping(address => bool) public BlackList;
event AddressAddedToBlackList(address indexed account);
event AddressRemovedFromBlackList(address indexed account);
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "Only the owner can modify the BlackList");
_;
}
function addToBlackList(address _account) public onlyOwner {
BlackList[_account] = true;
emit AddressAddedToBlackList(_account);
}
function removeFromBlackList(address _account) public onlyOwner {
BlackList[_account] = false;
emit AddressRemovedFromBlackList(_account);
}
}
Detection Tips:Event Logging: Look for events that record blacklisting actions. Events provide transparency and are very important for monitoring contract actions. You could say that this is the safest kind of BlackList as developers do not hide this function but openly log all its calls in event logs.
Example 5: Blacklist with Whitelist functions (Whitelist)
contract TokenWithBlackListAndWhitelist {
address public owner;
mapping(address => bool) public BlackList;
mapping(address => bool) public whitelist;
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "Only the owner can modify the lists");
_;
}
function addToBlackList(address _account) public onlyOwner {
BlackList[_account] = true;
}
function removeFromBlackList(address _account) public onlyOwner {
BlackList[_account] = false;
}
function addToWhitelist(address _account) public onlyOwner {
whitelist[_account] = true;
}
function removeFromWhitelist(address _account) public onlyOwner {
whitelist[_account] = false;
}
}
Detection Tips:Whitelist functionality: Pay attention to contracts that have both blacklisting and whitelisting functions at the same time. Such dual functionality may have implications for token transfers without the owner's knowledge or other fraudulent activities.
Example 6: Blacklist with Governance Control (Governance Control)
interface Governance {
function canBlackList(address _caller) external view returns (bool);
}
contract TokenWithGovernanceControl {
address public owner;
address public governanceContract;
mapping(address => bool) public BlackList;
constructor(address _governanceContract) {
owner = msg.sender;
governanceContract = _governanceContract;
}
modifier onlyOwnerOrGovernance() {
require(msg.sender == owner || Governance(governanceContract).canBlackList(msg.sender), "Not authorized");
_;
}
function addToBlackListGoverned(address _account) public onlyOwnerOrGovernance {
BlackList[_account] = true;
}
function removeFromBlackList(address _account) public onlyOwnerOrGovernance {
BlackList[_account] = false;
}
}
Detection Tips:Identify contracts where blacklisting activities are subject to control by external contract managers. When considering a smart contract, carefully analyze the code, paying attention to access controls, payment mechanisms, time-dependent terms and conditions, event logging, anti-circumvention protections, and other important factors. In addition, consider the specifics of the project and its goals when assessing the implications of using the blacklist functions.
Example 7: Blacklist with Emergency Stop
contract TokenWithEmergencyStop {
address public owner;
bool public emergencyStop;
mapping(address => bool) public BlackList;
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "Only the owner can modify the BlackList");
_;
}
modifier whenNotPaused() {
require(!emergencyStop, "Contract is paused");
_;
}
function addToBlackList(address _account) public onlyOwner whenNotPaused {
BlackList[_account] = true;
}
function removeFromBlackList(address _account) public onlyOwner whenNotPaused {
BlackList[_account] = false;
}
function toggleEmergencyStop() public onlyOwner {
emergencyStop = !emergencyStop;
}
}
Detection Tips:The crash pause mechanism may pause some functions, including blacklist changes.
Example 8: Blacklist with dynamic conditions
contract TokenWithDynamicBlackList {
address public owner;
mapping(address => bool) public BlackList;
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "Only the owner can modify the BlackList");
_;
}
function conditionallyBlackList(address _account, uint256 _threshold) public onlyOwner {
require(getBalance(_account) < _threshold, "Account balance exceeds threshold");
BlackList[_account] = true;
}
function removeFromBlackList(address _account) public onlyOwner {
BlackList[_account] = false;
}
}
Detection Tips:Blacklisting can often be based on certain conditions or events. Carefully study the functions that are checked before activating the Blacklist. These functions contain the logic for adding the owner to the Blacklist, in this example the condition for adding is that the account balance is above the specified threshold.
Example 9: Time-Locked Removal Blacklist (Time-Locked Removal)
contract TokenWithTimeLockedRemoval {
address public owner;
mapping(address => bool) public BlackList;
mapping(address => uint256) public removalTimeLock;
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "Only the owner can modify the BlackList");
_;
}
function addToBlackList(address _account) public onlyOwner {
BlackList[_account] = true;
removalTimeLock[_account] = block.timestamp + 7 days;
}
function removeFromBlackList(address _account) public onlyOwner {
require(block.timestamp >= removalTimeLock[_account], "Time lock not expired");
BlackList[_account] = false;
removalTimeLock[_account] = 0;
}
}
Detection Tips:Identify contracts where blacklist removal is time-limited. Often in such cases, time calculations based on block.timestamp are used.
Example 10: Blacklist with gas limits (Gas Limit Protection)
contract TokenWithGasLimitProtection {
address public owner;
mapping(address => bool) public BlackList;
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "Only the owner can modify the BlackList");
_;
}
modifier limitGas() {
require(gasleft() >= 100000, "Insufficient gas");
_;
}
function addToBlackListGasLimited(address _account) public onlyOwner limitGas {
BlackList[_account] = true;
}
function removeFromBlackList(address _account) public onlyOwner {
BlackList[_account] = false;
}
}
Detection Tips:Identify contracts where certain functions, such as blacklisting, are subject to gas limits.
Example 11: Blacklist with external integration with Oracle (Oracle)
interface Oracle {
function isBlackListed(address _account) external view returns (bool);
}
contract TokenWithOracleIntegration {
address public owner;
Oracle public oracle;
constructor(address _oracleAddress) {
owner = msg.sender;
oracle = Oracle(_oracleAddress);
}
modifier onlyOwner() {
require(msg.sender == owner, "Only the owner can modify the BlackList");
_;
}
function addToBlackListByOracle(address _account) public onlyOwner {
require(oracle.isBlackListed(_account), "Oracle did not confirm BlackListing");
}
}
Detection Tips:Be careful of contracts that rely on external Oracles to make blacklisting decisions. Always check the reliability and transparency of the Oracles that a smart contract uses.
Example 12: Blacklisting with interaction with an external contract
interface ExternalContract {
function addToBlackList(address _account) external;
function removeFromBlackList(address _account) external;
}
contract TokenWithExternalInteraction {
address public owner;
ExternalContract public externalContract;
constructor(address _externalContract) {
owner = msg.sender;
externalContract = ExternalContract(_externalContract);
}
modifier onlyOwner() {
require(msg.sender == owner, "Only the owner can modify the BlackList");
_;
}
function addToBlackListExternal(address _account) public onlyOwner {
externalContract.addToBlackList(_account);
}
function removeFromBlackListExternal(address _account) public onlyOwner {
externalContract.removeFromBlackList(_account);
}
}
Detection Tips:When making blacklisting decisions, be careful of contracts that interact with external contracts, especially if the source code of the external contract is not verified.
Example 13: Blacklist with Dynamic Threshold (Dynamic Threshold)
contract TokenWithDynamicThreshold {
address public owner;
mapping(address => bool) public BlackList;
uint256 public dynamicThreshold;
constructor(uint256 _initialThreshold) {
owner = msg.sender;
dynamicThreshold = _initialThreshold;
}
modifier onlyOwner() {
require(msg.sender == owner, "Only the owner can modify the BlackList");
_;
}
function addToBlackListDynamicThreshold(address _account) public onlyOwner {
require(getBalance(_account) > dynamicThreshold, "Account balance is below threshold");
BlackList[_account] = true;
}
function removeFromBlackList(address _account) public onlyOwner {
BlackList[_account] = false;
}
function updateDynamicThreshold(uint256 _newThreshold) public onlyOwner {
dynamicThreshold = _newThreshold;
}
}
Detection Tips:Identify contracts where the blacklisting threshold is dynamic and can be set by the owner over time (by calling certain contract methods).
General tips for identifying Black List functions (BlackList)
-
Look for functions that modify the address list (mapping):
Examine the smart contract code to identify functions that modify the address list, such as adding or removing addresses. -
Check for Owner-only access:
Blacklist functions often have access restrictions that allow only the contract owner or administrators to execute them. Look for the use of the onlyOwner modifier or similar access control mechanisms. -
Check the constructor() constructor function:
The constructor function specifies the initial state of the contract. Check to see if any address bindings or lists are initialized in the constructor, indicating a blacklist. -
Explore the logic of modifiers:
Analyze the logic of modifiers of type onlyOwner to understand under what conditions functions related to blacklisting can be performed. -
Find key terms:
Look for keywords such as "BlackList", "addBlackList", "removeBlackList" or similar terms in the smart contract code (in the simplest cases these functions have similar names, in more complex variants the names may not reflect the essence of the function to disguise it). -
Check documentation and comments:
Review the documentation and contract comments for any mention of blacklisting functions. Developers often provide information on how certain functions, including blacklisting, should be used. -
Check external calls (call) or events (event):
Look for external calls or events that may be triggered when an address is added to or removed from the blacklist. This can provide insight into how the contract interacts with external components based on the actions associated with the blacklist. -
Assess the update and management capabilities of the contract code:
Evaluate the smart contract for update mechanisms or governance structures that allow for changes to its blacklisting logic. Understanding how updates are managed is critical to anticipating potential changes to blacklist functionality. -
Check the blacklist logic in other functions:
Examine other functions in the contract for checks to determine if an address is blacklisted before performing certain actions. -
Discover the use cases and tokenomics:
Understand the usage scenarios and tokenomics of the project. If the project is related to user address management or has functions related to user rights, there may be a reason for blacklisting. -
Event logging:
Note the presence of an event log associated with blacklisting actions. Events are often used to log significant state changes, providing transparency into contract behavior. -
Gas Limit Protection:
Use caution with functions that have gas limit protection. While this may be an implementation of a safety feature, it can also be used to control or limit the performance of some critical contract functions. -
Time-dependent conditions:
Check for time-dependent conditions related to blacklisting. For example, contracts may implement time locks on deletion or other time-sensitive mechanisms. -
Independent audits:
Look for smart contracts that have been independently audited by reputable auditing firms. Audit reports provide insight into the security and functionality of the contract. -
Review community feedback:
Check community forums, social media, or official communication channels for discussions about the presence and use of the blacklist functions. Users can provide valuable insights and concerns.
When analyzing a smart contract, it is critical to have a full understanding of its features and functionality. These tips will help you identify and evaluate the presence of blacklist functions, allowing you to make informed decisions about interacting with the contract.
Where possible, choose contracts that comply with established standards (e.g. ERC-20). These standards are often scrutinized and have a reputation for reliability.
We hope these examples have helped you better understand Black List schemes (BlackList) in smart contracts.
Since all information in the blockchain is open (provided, of course, that the source code of the contract is verified), armed with this knowledge you can independently study smart contracts and identify various scam schemes.
However, we've already done it all for you! Sign up for a premium subscription and get access to exclusive filters on smart contract functions and fresh analytics. Increase your chances of successfully investing in profitable tokens.
Regards, Lotus Market team.
All posts