### Solhint Linter Configuration Example Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README-vi.md An example of how to configure Solhint, a linter for Solidity code, to enforce security and style guidelines. Solhint is written in JavaScript. ```JavaScript // .solhint.json { "extends": "solhint:recommended", "rules": { "compiler-version": [ "error", "^0.8.0" ], "func-visibility": [ "warn", "external" ], "no-inline-assembly": "off", "no-unused-vars": [ "warn", { "ignorePattern": "^_" } ] } } ``` -------------------------------- ### Solidity Logic Contract Example Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/precautions/upgradeability.md A simple Solidity contract that can be called via DELEGATECALL. This example includes a counter that can be incremented, demonstrating state modification within the context of the calling contract. ```solidity contract LogicContract { address public currentVersion; address public owner; uint public counter; function incrementCounter() { counter++; } } ``` -------------------------------- ### Build Documentation Site Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README.md Clones the repository, installs dependencies using pip, and builds the documentation site using mkdocs. ```shell git clone git@github.com:ConsenSys/smart-contract-best-practices.git cd smart-contract-best-practices pip install -r requirements.txt mkdocs build ``` -------------------------------- ### Serve Documentation Site Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README.md Runs the mkdocs serve command to start a local development server, automatically restarting on file changes or errors. ```shell until mkdocs serve; do : ; done ``` -------------------------------- ### Keccak256 Hash Example Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/general/public-data.md Demonstrates the keccak256 hash of the string 'rock'. This example highlights how a direct hash might be predictable and suggests using a salt for better security in commit-reveal schemes. ```text The keccak256 hash of `rock` is: 10977e4d68108d418408bc9310b60fc6d0a750c63ccef42cfb0ead23ab73d102. A safer implementation would be to hash not just the name of the move, but also, say, a user chosen salt. ``` -------------------------------- ### Uniswap V2 Sliding Window Oracle Example Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/attacks/oracle-manipulation.md An example implementation of a sliding window oracle for Uniswap V2, demonstrating how to fetch time-weighted average prices to mitigate manipulation. This contract is part of the Uniswap V2 periphery library. ```solidity // This is a conceptual reference to a Solidity example. // The actual code can be found at: // https://github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/examples/ExampleSlidingWindowOracle.sol // ExampleSlidingWindowOracle.sol // Provides a basic implementation of a sliding window oracle for Uniswap V2. // It allows querying the time-weighted average price (TWAP) of an asset pair. // This helps in preventing price manipulation by averaging prices over a period. // Key components typically include: // - Initialization of the oracle with a Uniswap V2 pair. // - Functions to update the oracle with new price observations. // - A function to query the TWAP over a specified period. // Note: This is a placeholder representing the linked contract. The full Solidity code is extensive. ``` -------------------------------- ### Executor Contract Example (Mitigation) Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/attacks/griefing.md An example Solidity contract that can be called by a Relayer. It includes a check for sufficient gas using gasleft() to prevent griefing attacks by ensuring enough gas is available for execution. ```Solidity // contract called by Relayer contract Executor { function execute(bytes _data, uint _gasLimit) { require(gasleft() >= _gasLimit); ... } } ``` -------------------------------- ### Solidity Multiple Inheritance Linearization Example Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/solidity-specific/complex-inheritance.md Demonstrates a Solidity contract structure with multiple inheritance, illustrating how the inheritance graph is linearized. This example shows how the order of inheritance affects function resolution, specifically the 'fee' variable and 'setFee' function, and the potential for unexpected behavior or security issues. ```Solidity contract Final { uint public a; function Final(uint f) public { a = f; } } contract B is Final { int public fee; function B(uint f) Final(f) public { } function setFee() public { fee = 3; } } contract C is Final { int public fee; function C(uint f) Final(f) public { } function setFee() public { fee = 5; } } contract A is B, C { function A() public B(3) C(5) { setFee(); } } ``` -------------------------------- ### Solidity Registry Contract for Upgrades Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/precautions/upgradeability.md An example Solidity contract that acts as a registry to store the address of the latest backend contract. It includes owner-based modification of the backend address and maintains a history of previous contract versions. ```solidity pragma solidity ^0.5.0; contract SomeRegister { address backendContract; address[] previousBackends; address owner; constructor() { owner = msg.sender; } modifier onlyOwner() { require(msg.sender == owner) _; } function changeBackend(address newBackend) public onlyOwner() returns (bool) { if(newBackend != address(0) && newBackend != backendContract) { previousBackends.push(backendContract); backendContract = newBackend; return true; } return false; } } ``` -------------------------------- ### Commit-Reveal Scheme Use Cases Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/general/public-data.md Provides examples of how commit-reveal schemes can be applied in different scenarios, such as rock-paper-scissors games, auctions, and applications requiring random number generation. ```text - In rock paper scissors, require both players to submit a hash of their intended move first, then require both players to submit their move; if the submitted move does not match the hash throw it out. - In an auction, require players to submit a hash of their bid value in an initial phase (along with a deposit greater than their bid value), and then submit their auction bid value in the second phase. - When developing an application that depends on a random number generator, the order should always be *(1)* players submit moves, *(2)* random number generated, *(3)* players paid out. ``` -------------------------------- ### Solidity: Simple Fallback Function for Ether Deposit Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/solidity-specific/fallback-functions.md Demonstrates how to implement a simple fallback function in Solidity to receive Ether, emphasizing the gas limit and logging events. It contrasts a bad example with good practices for handling Ether deposits. ```solidity // bad function() payable { balances[msg.sender] += msg.value; } // good function deposit() payable external { balances[msg.sender] += msg.value; } function() payable { require(msg.data.length == 0); emit LogDepositReceived(msg.sender); } ``` -------------------------------- ### Insecure Reentrancy Example (Solidity) Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README-vi.md Demonstrates an insecure pattern where a reentrancy vulnerability can be exploited. The `getFirstWithdrawalBonus` function calls `withdrawReward` before updating the `claimedBonus` state, allowing recursive calls. ```solidity mapping (address => uint) private userBalances; mapping (address => bool) private claimedBonus; mapping (address => uint) private rewardsForA; function withdrawReward(address recipient) public { uint amountToWithdraw = rewardsForA[recipient]; rewardsForA[recipient] = 0; (bool success, ) = recipient.call.value(amountToWithdraw)(""); require(success); } function getFirstWithdrawalBonus(address recipient) public { require(!claimedBonus[recipient]); // Each recipient should only be able to claim the bonus once rewardsForA[recipient] += 100; withdrawReward(recipient); // At this point, the caller will be able to execute getFirstWithdrawalBonus again. claimedBonus[recipient] = true; } ``` -------------------------------- ### Solidity Signed Integer Negation Example Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/general/negative-int.md Demonstrates the behavior of negating the minimum value for Solidity's signed integer types (`int8`, `int16`). It highlights how negating the most negative number in two's complement representation results in the same number, and shows example usage within a contract. ```solidity contract Negation { function negate8(int8 _i) public pure returns(int8) { return -_i; } function negate16(int16 _i) public pure returns(int16) { return -_i; } int8 public a = negate8(-128); // -128 int16 public b = negate16(-128); // 128 int16 public c = negate16(-32768); // -32768 } ``` -------------------------------- ### Handle Low-Level Call Failures in JavaScript Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README-vi.md Demonstrates how to safely use low-level calls like `address.call()` and `address.send()` in JavaScript. These methods return `false` on failure instead of throwing exceptions. It's crucial to check the return value to handle potential call failures and avoid unexpected transaction behavior. The example also highlights the danger of forwarding all gas without checking results. ```javascript // bad someAddress.send(55); someAddress.call.value(55)(""); // this is doubly dangerous, as it will forward all remaining gas and doesn't check for result someAddress.call.value(100)(bytes4(sha3('deposit()'))); // if deposit throws an exception, the raw call() will only return false and transaction will NOT be reverted // good (bool success, ) = someAddress.call.value(55)(""); if(!success) { // handle failure code } ExternalContract(someAddress).deposit.value(100)(); ``` -------------------------------- ### Integer Division Handling in Solidity Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/solidity-specific/integer-division.md Demonstrates how integer division in Solidity rounds down to the nearest integer. It provides examples of the 'bad' practice and recommended 'good' practices using multipliers or storing numerator and denominator separately for off-chain calculations. ```sol // bad uint x = 5 / 2; // Result is 2, all integer division rounds DOWN to the nearest integer ``` ```sol // good uint multiplier = 10; uint x = (5 * multiplier) / 2; ``` ```sol // good uint numerator = 5; uint denominator = 2; ``` -------------------------------- ### Proper Use of assert(), require(), revert() in Solidity Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/solidity-specific/assert-require-revert.md Explains the distinct roles of `assert()` for internal errors and invariants, and `require()` for validating external conditions and inputs in Solidity. It provides an example showing how `require()` validates inputs and external calls, while `assert()` checks internal state consistency. ```solidity pragma solidity ^0.5.0; contract Sharer { function sendHalf(address payable addr) public payable returns (uint balance) { require(msg.value % 2 == 0, "Even value required."); //Require() can have an optional message string uint balanceBeforeTransfer = address(this).balance; (bool success, ) = addr.call.value(msg.value / 2)(""); require(success); // Since we reverted if the transfer failed, there should be // no way for us to still have half of the money. assert(address(this).balance == balanceBeforeTransfer - msg.value / 2); // used for internal error checking return address(this).balance; } } ``` -------------------------------- ### Solidity Assert and Require Usage Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README-vi.md Illustrates the correct application of `require()` for validating inputs and external call results, and `assert()` for checking internal states and invariants. The example shows a `sendHalf` function that uses `require` to ensure an even Ether value is sent and `assert` to verify the contract's balance remains consistent after a transfer, preventing unexpected internal errors. ```Solidity pragma solidity ^0.5.0; contract Sharer { function sendHalf(address payable addr) public payable returns (uint balance) { require(msg.value % 2 == 0, "Even value required."); //Require() can have an optional message string uint balanceBeforeTransfer = address(this).balance; addr.transfer(msg.value / 2); // Since transfer throws an exception on failure and // cannot call back here, there should be no way for us to // still have half of the money. assert(address(this).balance == balanceBeforeTransfer - msg.value / 2); // used for internal error checking return address(this).balance; } } ``` -------------------------------- ### Insecure Mutex Example with Multiple Contracts (Solidity) Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README-vi.md Illustrates a potential pitfall when using mutexes across multiple interacting contracts. The `StateHolder` contract's lock mechanism can be bypassed if not carefully managed, leading to reentrancy issues. ```solidity contract StateHolder { uint private n; address private lockHolder; function getLock() { require(lockHolder == address(0)); lockHolder = msg.sender; } function releaseLock() { require(msg.sender == lockHolder); lockHolder = address(0); } function set(uint newState) { require(msg.sender == lockHolder); n = newState; } } ``` -------------------------------- ### Solidity Rate Limiting Example Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/precautions/rate-limiting.md This Solidity code snippet demonstrates a basic rate-limiting mechanism for smart contracts. It prevents excessive withdrawals within a defined time period by tracking withdrawn amounts against a limit. The implementation uses block numbers to manage time periods and requires constructor arguments for the period duration and withdrawal limit. ```solidity uint internal period; // how many blocks before limit resets uint internal limit; // max ether to withdraw per period uint internal currentPeriodEnd; // block which the current period ends at uint internal currentPeriodAmount; // amount already withdrawn this period constructor(uint _period, uint _limit) public { period = _period; limit = _limit; currentPeriodEnd = block.number + period; } function withdraw(uint amount) public { // Update period before proceeding updatePeriod(); // Prevent overflow uint totalAmount = currentPeriodAmount + amount; require(totalAmount >= currentPeriodAmount, 'overflow'); // Disallow withdraws that exceed current rate limit require(currentPeriodAmount + amount < limit, 'exceeds period limit'); currentPeriodAmount += amount; msg.sender.transfer(amount); } function updatePeriod() internal { if(currentPeriodEnd < block.number) { currentPeriodEnd = block.number + period; currentPeriodAmount = 0; } } ``` -------------------------------- ### Relayer Contract Example (Griefing Attack) Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/attacks/griefing.md A simplified Solidity contract demonstrating a potential griefing attack vector. The Relayer contract uses address.call() and continues execution even if the sub-call fails, allowing an attacker to exploit gas limits. ```Solidity contract Relayer { mapping (bytes => bool) executed; function relay(bytes _data) public { // replay protection; do not call the same transaction twice require(executed[_data] == 0, "Duplicate call"); executed[_data] = true; innerContract.call(bytes4(keccak256("execute(bytes)")), _data); } } ``` -------------------------------- ### Solidity Visibility: Explicit Function and Variable Labeling Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/solidity-specific/visibility.md Demonstrates best practices for explicitly labeling function and state variable visibility in Solidity. Covers `external`, `public`, `internal`, and `private` keywords, explaining their differences and providing examples of 'bad' vs. 'good' practices for clarity and security. ```solidity // bad uint x; // the default is internal for state variables, but it should be made explicit function buy() { // the default is public // public code } // good uint private y; function buy() external { // only callable externally or using this.buy() } function utility() public { // callable externally, as well as internally: changing this code requires thinking about both cases. } function internalAction() internal { // internal code } ``` -------------------------------- ### Solidity Contract Example: Unexpected Ether Receipt Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/attacks/force-feeding.md Demonstrates a Solidity contract with a payable receive() function that reverts, yet Ether can still be sent to the contract via EVM-level operations. ```solidity pragma solidity ^0.8.13; contract Vulnerable { receive() external payable { revert(); } function somethingBad() external { require(address(this).balance > 0); // Do something bad } } ``` -------------------------------- ### Solidity: Secure Authorization with msg.sender vs tx.origin Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/solidity-specific/tx-origin.md Illustrates a critical smart contract security vulnerability where `tx.origin` is misused for authorization. The example includes a vulnerable `MyContract` and an `AttackingContract` to exploit it, highlighting why `msg.sender` is the preferred and secure method for authorization. ```solidity contract MyContract { address owner; function MyContract() public { owner = msg.sender; } function sendTo(address receiver, uint amount) public { require(tx.origin == owner); (bool success, ) = receiver.call.value(amount)(""); require(success); } } contract AttackingContract { MyContract myContract; address attacker; function AttackingContract(address myContractAddress) public { myContract = MyContract(myContractAddress); attacker = msg.sender; } function() public { myContract.sendTo(attacker, msg.sender.balance); } } ``` -------------------------------- ### Solidity Modifier for Automatic Deprecation Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README-vi.md An example of using a Solidity modifier to enforce a time-based deprecation for contract functions. This ensures that certain actions are only allowed up to a specific block number. ```solidity modifier isActive() { require(block.number <= SOME_BLOCK_NUMBER); _; } function deposit() public isActive { // some code } function withdraw() public { // some code } ``` -------------------------------- ### Solidity Timestamp Manipulation Example Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/solidity-specific/timestamp-dependence.md This Solidity code snippet demonstrates a function that uses `block.timestamp` and `block.number` to generate a pseudo-random number. It highlights how miners can manipulate `block.timestamp` within a 15-second window to gain an advantage in lottery-like scenarios, making such implementations insecure. ```Solidity uint256 constant private salt = block.timestamp; function random(uint Max) constant private returns (uint256 result){ //get the best seed for randomness uint256 x = salt * 100/Max; uint256 y = salt * block.number/(salt % 5) ; uint256 seed = block.number/3 + (salt % 300) + Last_Payout + y; uint256 h = uint256(block.blockhash(seed)); return uint256((h / x)) % Max + 1; //random number between 1 and Max } ``` -------------------------------- ### Solidity Withdrawal Speed Bump Example Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/precautions/speed-bumps.md Demonstrates a 'speed bump' pattern in Solidity to delay fund withdrawals. This mechanism provides a grace period after a withdrawal request, allowing time for potential recovery actions against malicious activity. It utilizes mappings for tracking balances and requested withdrawals, and `block.timestamp` to enforce the delay. ```solidity struct RequestedWithdrawal { uint amount; uint time; } mapping (address => uint) private balances; mapping (address => RequestedWithdrawal) private requestedWithdrawals; uint constant withdrawalWaitPeriod = 28 days; // 4 weeks function requestWithdrawal() public { if (balances[msg.sender] > 0) { uint amountToWithdraw = balances[msg.sender]; balances[msg.sender] = 0; // for simplicity, we withdraw everything; // presumably, the deposit function prevents new deposits when withdrawals are in progress requestedWithdrawals[msg.sender] = RequestedWithdrawal({ amount: amountToWithdraw, time: block.timestamp }); } } function withdraw() public { if(requestedWithdrawals[msg.sender].amount > 0 && block.timestamp > requestedWithdrawals[msg.sender].time + withdrawalWaitPeriod) { uint amountToWithdraw = requestedWithdrawals[msg.sender].amount; requestedWithdrawals[msg.sender].amount = 0; require(msg.sender.send(amountToWithdraw)); } } ``` -------------------------------- ### Solidity Integer Negation Edge Case Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README-vi.md Demonstrates the behavior of negating the minimum integer value in Solidity (e.g., int8, int16). Due to two's complement representation, negating the smallest negative number results in the same smallest negative number for certain types. The example shows how to handle this by checking values before negation or using wider integer types. ```Solidity contract Negation { function negate8(int8 _i) public pure returns(int8) { return -_i; } function negate16(int16 _i) public pure returns(int16) { return -_i; } int8 public a = negate8(-128); // -128 int16 public b = negate16(-128); // 128 int16 public c = negate16(-32768); // -32768 } ``` -------------------------------- ### Solidity Circuit Breaker Implementation Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/precautions/circuit-breakers.md Demonstrates a circuit breaker pattern in Solidity. It uses a boolean flag and modifiers to control contract execution, allowing trusted parties to trigger the breaker or programmatic rules to activate it. The example includes functions for depositing and withdrawing, protected by the circuit breaker. ```solidity bool private stopped = false; address private owner; modifier isAdmin() { require(msg.sender == owner); _; } function toggleContractActive() isAdmin public { // You can add an additional modifier that restricts stopping a contract to be based on another action, such as a vote of users stopped = !stopped; } modifier stopInEmergency { if (!stopped) _; } modifier onlyInEmergency { if (stopped) _; } function deposit() stopInEmergency public { // some code } function withdraw() onlyInEmergency public { // some code } ``` -------------------------------- ### DoS via Block Gas Limit in Payouts Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README-zh.md Addresses the risk of hitting the block gas limit when processing large arrays for payouts. The example shows a method to mitigate this by processing a limited number of payees per transaction and tracking the progress using `nextPayeeIndex`, ensuring that the operation can be resumed if interrupted. ```Solidity struct Payee { address addr; uint256 value; } Payee payees[]; uint256 nextPayeeIndex; function payOut() { uint256 i = nextPayeeIndex; while (i < payees.length && msg.gas > 200000) { payees[i].addr.send(payees[i].value); i++; } nextPayeeIndex = i; } ``` -------------------------------- ### DoS via Unexpected Throw in Auction Contract Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README-zh.md An auction contract example where a DoS vulnerability can be exploited. If the refund transaction to the previous leader fails (e.g., due to the recipient's contract having a fallback function that reverts), the `bid()` function will throw, preventing anyone from bidding further and effectively freezing the auction. ```Solidity contract Auction { address currentLeader; uint highestBid; function bid() payable { if (msg.value <= highestBid) { throw; } if (!currentLeader.send(highestBid)) { throw; } // Refund the old leader, and throw if it fails currentLeader = msg.sender; highestBid = msg.value; } } ``` -------------------------------- ### Redeploy Documentation Site Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README.md Deploys the built documentation site to GitHub Pages using the mkdocs gh-deploy command. ```shell mkdocs gh-deploy ``` -------------------------------- ### Git Workflow for Contributions Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/CONTRIBUTING.md A series of bash commands essential for contributing to the project, including forking, cloning, setting up remotes, fetching upstream changes, creating topic branches, merging, and pushing. ```bash # Clone your fork of the repo into the current directory git clone https://github.com// # Navigate to the newly cloned directory cd # Assign the original repo to a remote called "upstream" git remote add upstream https://github.com// ``` ```bash git checkout git pull upstream ``` ```bash git checkout -b ``` ```bash git pull [--rebase] upstream ``` ```bash git push origin ``` -------------------------------- ### DELEGATECALL Considerations and Best Practices Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/precautions/upgradeability.md Key considerations and potential pitfalls when using DELEGATECALL for upgradeable contracts, focusing on storage layout, inheritance, constructors, and ABI encoding. ```APIDOC DELEGATECALL Usage and Security Considerations: DELEGATECALL executes code from another contract within the context of the calling contract. This means storage, msg.sender, and msg.value remain the same, but the code executed is from the target address. Key Considerations: - Storage Layout: - The storage layout of the calling contract (e.g., Proxy) and the called contract (e.g., Logic) must be compatible. - New variables should only be appended to the end of the storage layout in subsequent versions to avoid overwriting existing data. - Understand how the EVM handles state variable packing and inheritance order, as these affect storage slot allocation. - Constructors: - Constructors are only executed once when a contract is deployed. They are NOT executed when DELEGATECALL is used. - Function Selectors and Collisions: - Be aware of function selector collisions between the proxy and logic contracts, as this can lead to unintended function execution or denial of service. - Malicious backdoors can be introduced if function signatures are not carefully managed. - Return Values: - Simple DELEGATECALL implementations might not easily return values from the called contract's functions. More complex patterns involving inline assembly are needed for this. - Error Handling: - DELEGATECALL to a non-existent contract returns 'true' without reverting, even if the called code fails. Proper error checking (e.g., `require(success)`) is crucial. Related Concepts: - Proxy Patterns: General strategies for contract upgradeability, often employing DELEGATECALL. - Router/Dispatcher Contracts: Implementations that manage multiple logic contracts or versions. - Immutability and Trustlessness: The importance of immutability in achieving trustless systems, and how upgradeability can impact this. References: - [Proxy Patterns](https://blog.openzeppelin.com/proxy-patterns/) - [Breaking the proxy pattern](https://blog.trailofbits.com/2018/09/05/contract-upgrade-anti-patterns/) - [Solidity storage layout](https://docs.solidity.org/en/latest/internals/layout_in_storage.html) - [Solidity fallback function](https://docs.solidity.readthedocs.io/en/latest/contracts.html#fallback-function) ``` -------------------------------- ### Solidity: `OnlyForEOA` Contract Exploiting `extcodesize` Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/solidity-specific/extcodesize-checks.md An example of a Solidity contract `OnlyForEOA` that uses a vulnerable `isNotContract` modifier. This contract can be tricked by a `FakeEOA` contract calling its protected function during deployment. ```solidity contract OnlyForEOA { uint public flag; // bad modifier isNotContract(address _a){ uint len; assembly { len := extcodesize(_a) } require(len == 0); _; } function setFlag(uint i) public isNotContract(msg.sender){ flag = i; } } ``` -------------------------------- ### Solidity Relay Contract for DELEGATECALL Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/precautions/upgradeability.md A Solidity contract demonstrating how to use DELEGATECALL to forward calls and data to a logic contract. It includes owner-based upgrade functionality and a fallback function to handle incoming calls. ```solidity pragma solidity ^0.5.0; contract Relay { address public currentVersion; address public owner; modifier onlyOwner() { require(msg.sender == owner); _; } constructor(address initAddr) { require(initAddr != address(0)); currentVersion = initAddr; owner = msg.sender; // this owner may be another contract with multisig, not a single contract owner } function changeContract(address newVersion) public onlyOwner() { require(newVersion != address(0)); currentVersion = newVersion; } fallback() external payable { (bool success, ) = address(currentVersion).delegatecall(msg.data); require(success); } } ``` -------------------------------- ### Solidity: Cross-Function Reentrancy Vulnerability Example Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/attacks/reentrancy.md Demonstrates cross-function reentrancy where an attacker can exploit shared state between two functions. By calling `transfer` during the external call in `withdrawBalance`, the attacker can move funds before their balance is zeroed out. ```Solidity mapping (address => uint) private userBalances; function transfer(address to, uint amount) { if (userBalances[msg.sender] >= amount) { userBalances[to] += amount; userBalances[msg.sender] -= amount; } } function withdrawBalance() public { uint amountToWithdraw = userBalances[msg.sender]; (bool success, ) = msg.sender.call.value(amountToWithdraw)(""); // At this point, the caller's code is executed, and can call transfer() require(success); userBalances[msg.sender] = 0; } ``` -------------------------------- ### Register Contract for Upgrades Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README-zh.md A simple registration contract that stores the address of the latest backend contract. Users must manually fetch the new address to interact with the updated contract. This method requires careful consideration for data migration. ```solidity contract SomeRegister { address backendContract; address[] previousBackends; address owner; function SomeRegister() { owner = msg.sender; } modifier onlyOwner() { if (msg.sender != owner) { throw; } _; } function changeBackend(address newBackend) public onlyOwner() returns (bool) { if(newBackend != backendContract) { previousBackends.push(backendContract); backendContract = newBackend; return true; } return false; } } ``` -------------------------------- ### Python: Deterministic Contract Address Generation Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/attacks/force-feeding.md Illustrates the Python logic used in EVM implementations to generate a contract's address deterministically based on the deployer's address and nonce. ```python from eth_utils import keccak import rlp def generate_contract_address(address: Address, nonce: int) -> Address: return force_bytes_to_address(keccak(rlp.encode([address, nonce]))) # Example Usage: # deployer_address = '0x...' # Address of the deployer # contract_nonce = 0 # Nonce of the deployer # contract_address = generate_contract_address(deployer_address, contract_nonce) # print(f"Generated contract address: {contract_address}") ``` -------------------------------- ### Security Analysis Tools Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README-zh.md Tools to analyze Ethereum smart contracts for common vulnerabilities and visualize control flow. ```APIDOC Oyente: Description: Analyzes Ethereum code to find common vulnerabilities. Reference: http://www.comp.nus.edu.sg/~loiluu/papers/oyente.pdf Solgraph: Description: Generates a DOT graph showing the control flow of Solidity contract functions and highlights potential security vulnerabilities. Usage: Generates a visual representation of contract logic for security review. ``` -------------------------------- ### Solidity: Basic Charity Contract with Donate Function Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/solidity-specific/event-monitoring.md Demonstrates a basic Solidity contract for receiving donations. It maps addresses to their balance and allows users to send Ether to the contract. ```solidity contract Charity { mapping(address => uint) balances; function donate() payable public { balances[msg.sender] += msg.value; } } contract Game { function buyCoins() payable public { // 5% goes to charity charity.donate.value(msg.value / 20)(); } } ``` -------------------------------- ### Initialize Google Tag Manager Script (JavaScript) Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/custom/partials/integrations/analytics/custom.html This snippet initializes the Google Tag Manager script for tracking website events. It dynamically creates a script tag and appends it to the document's head. Requires a valid Google Tag Manager ID. ```javascript (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-MCQTD6XJ'); ``` -------------------------------- ### Solidity Coverage Testing Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README-zh.md Tool for measuring code coverage in Solidity smart contracts. ```APIDOC solidity-coverage: Description: Measures code coverage for Solidity smart contracts. Reference: https://github.com/sc-forks/solidity-coverage ``` -------------------------------- ### Ether Transfer Methods: send(), transfer(), call.value() Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README-zh.md Compares Solidity's methods for sending Ether. `transfer()` and `send()` are safer due to gas limits, while `call.value()` forwards all remaining gas, posing reentrancy risks. The text advises using `transfer()` or `send()` for Ether transfers and `call.value()` with caution, especially when dealing with untrusted contracts. ```solidity contract Example { // Recommended: Use transfer for Ether transfers function sendEtherTransfer(address payable recipient, uint amount) public payable { if (!recipient.transfer(amount)) { // Handle failure throw; } } // Also safe, but transfer is preferred as it's more explicit function sendEtherSend(address payable recipient, uint amount) public payable { if (!recipient.send(amount)) { // Handle failure throw; } } // Potentially unsafe: forwards all remaining gas, vulnerable to reentrancy function sendEtherCall(address payable recipient, uint amount) public payable { // This call forwards all remaining gas and can be dangerous if recipient is untrusted if (!recipient.call.value(amount)()) { // Handle failure throw; } } } ``` -------------------------------- ### Slither Static Analysis Tool Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README-vi.md Slither is a Python-based static analysis framework for Solidity smart contracts. It helps identify vulnerabilities and improve code quality. ```Python # Example usage of Slither (command-line) # Install Slither: pip install slither-analyzer # Analyze a contract: # slither your_contract.sol # Detect specific vulnerabilities (e.g., reentrancy): # slither --detect reentrancy your_contract.sol # Output in JSON format: # slither --json output.json your_contract.sol # Slither can also be used as a Python library: # from slither import Slither # slither = Slither('your_contract.sol') # for contract in slither.contracts: # for function in contract.functions: # print(f"Function: {function.name}") ``` -------------------------------- ### Solidity: Type Safety with Contract Addresses Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/solidity-specific/interface-types.md Illustrates how passing contract types or interfaces to Solidity functions provides better type safety compared to using raw addresses. The first part shows the correct way using a contract type, and the second part demonstrates the compiler error that occurs when an incompatible contract type is passed to a function expecting a specific contract type. ```solidity contract Validator { function validate(uint) external returns(bool); } contract TypeSafeAuction { // good function validateBet(Validator _validator, uint _value) internal returns(bool) { bool valid = _validator.validate(_value); return valid; } } contract TypeUnsafeAuction { // bad function validateBet(address _addr, uint _value) internal returns(bool) { Validator validator = Validator(_addr); bool valid = validator.validate(_value); return valid; } } ``` ```solidity contract NonValidator{} contract Auction is TypeSafeAuction { NonValidator nonValidator; function bet(uint _value) { // This call will result in a TypeError: // Invalid type for argument in function call. // Invalid implicit conversion from contract NonValidator to contract Validator requested. bool valid = validateBet(nonValidator, _value); } } ``` -------------------------------- ### Solidity Linters Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README-zh.md Tools to improve code quality by enforcing code style, typography, and identifying potential errors in Solidity contracts. ```APIDOC Solium: Description: A Solidity linter for code quality and style enforcement. Reference: https://github.com/duaraghav8/Solium Solint: Description: A Solidity linter that helps enforce code consistency conventions to avoid errors. Reference: https://github.com/weifund/solint Solcheck: Description: A Solidity linter written in JS, heavily influenced by ESLint, for code analysis. Reference: https://github.com/federicobond/solcheck ``` -------------------------------- ### DoS via Block Gas Limit: Payout with Iteration Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/attacks/denial-of-service.md Shows a pattern for handling payouts that might exceed the block gas limit. It iterates through a list of payees, processing a limited number per transaction to avoid hitting the gas limit, and tracks progress with `nextPayeeIndex`. ```solidity struct Payee { address addr; uint256 value; } Payee[] payees; uint256 nextPayeeIndex; function payOut() { uint256 i = nextPayeeIndex; while (i < payees.length && gasleft() > 200000) { payees[i].addr.send(payees[i].value); i++; } nextPayeeIndex = i; } ``` -------------------------------- ### Solidity Circuit Breaker for Rate Limiting Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README-vi.md A Solidity contract demonstrating rate limiting by implementing a circuit breaker pattern. It allows setting limits on transfers within a given period and manages pending transfers. ```solidity contract CircuitBreaker { struct Transfer { uint amount; address to; uint releaseBlock; bool released; bool stopped; } Transfer[] public transfers; address public curator; address public authorizedSender; uint public period; uint public limit; uint public currentPeriodEnd; uint public currentPeriodAmount; event PendingTransfer(uint id, uint amount, address to, uint releaseBlock); function CircuitBreaker(address _curator, address _authorizedSender, uint _period, uint _limit) { curator = _curator; period = _period; limit = _limit; authorizedSender = _authorizedSender; currentPeriodEnd = block.number + period; } function transfer(uint amount, address to) { if (msg.sender == authorizedSender) { updatePeriod(); if (currentPeriodAmount + amount > limit) { uint releaseBlock = block.number + period; PendingTransfer(transfers.length, amount, to, releaseBlock); transfers.push(Transfer(amount, to, releaseBlock, false, false)); } else { currentPeriodAmount += amount; transfers.push(Transfer(amount, to, block.number, true, false)); if(!to.send(amount)) throw; } } } function updatePeriod() { if (currentPeriodEnd < block.number) { currentPeriodEnd = block.number + period; currentPeriodAmount = 0; } } function releasePendingTransfer(uint id) { Transfer transfer = transfers[id]; if (transfer.releaseBlock <= block.number && !transfer.released && !transfer.stopped) { transfer.released = true; if(!transfer.to.send(transfer.amount)) throw; } } function stopTransfer(uint id) { if (msg.sender == curator) { transfers[id].stopped = true; } } } ``` -------------------------------- ### Solidity: Charity Contract with Event Logging Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/solidity-specific/event-monitoring.md Enhances the Charity contract by adding an event to log donation amounts. This allows for easier auditing and tracking of contributions. ```solidity contract Charity { // define event event LogDonate(uint _amount); mapping(address => uint) balances; function donate() payable public { balances[msg.sender] += msg.value; // emit event emit LogDonate(msg.value); } } contract Game { function buyCoins() payable public { // 5% goes to charity charity.donate.value(msg.value / 20)(); } } ``` -------------------------------- ### Speed Bumping (Delay Contract Actions) Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/README-zh.md Introduces a delay for certain actions, like withdrawals, to provide a window for recovery in case of malicious operations. This pattern is effective when combined with other security measures, as demonstrated by The DAO's withdrawal delay. ```solidity struct RequestedWithdrawal { uint amount; uint time; } mapping (address => uint) private balances; mapping (address => RequestedWithdrawal) private requestedWithdrawals; uint constant withdrawalWaitPeriod = 28 days; // 4 weeks function requestWithdrawal() public { if (balances[msg.sender] > 0) { uint amountToWithdraw = balances[msg.sender]; balances[msg.sender] = 0; // for simplicity, we withdraw everything; // presumably, the deposit function prevents new deposits when withdrawals are in progress requestedWithdrawals[msg.sender] = RequestedWithdrawal({ amount: amountToWithdraw, time: now }); } } function withdraw() public { if(requestedWithdrawals[msg.sender].amount > 0 && now > requestedWithdrawals[msg.sender].time + withdrawalWaitPeriod) { uint amountToWithdraw = requestedWithdrawals[msg.sender].amount; requestedWithdrawals[msg.sender].amount = 0; if(!msg.sender.send(amountToWithdraw)) { throw; } } } ``` -------------------------------- ### Solidity: Prefer Newer Constructs (selfdestruct, keccak256, transfer) Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/solidity-specific/event-monitoring.md Highlights preferred modern Solidity syntax and functions over older ones. It suggests using `selfdestruct` over `suicide` and `transfer()` over `send()` for Ether transfers. ```solidity // Prefer constructs/aliases such as `selfdestruct` (over `suicide`) and `keccak256` (over `sha3`). // Patterns like `require(msg.sender.send(1 ether))` can also be simplified to using `transfer()`, as in `msg.sender.transfer(1 ether)`. ``` -------------------------------- ### Handle Errors in Solidity External Calls Source: https://github.com/consensysdiligence/smart-contract-best-practices/blob/master/docs/development-recommendations/general/external-calls.md Demonstrates how to properly handle failures when using low-level Solidity call methods like address.call(). These methods return a boolean indicating success or failure, which must be checked to prevent unexpected transaction behavior. ```solidity // bad someAddress.send(55); someAddress.call.value(55)(""); // this is doubly dangerous, as it will forward all remaining gas and doesn't check for result someAddress.call.value(100)(bytes4(sha3("deposit() అధ్యక్ష"))); // if deposit throws an exception, the raw call() will only return false and transaction will NOT be reverted // good (bool success, ) = someAddress.call.value(55)(""); if(!success) { // handle failure code } ExternalContract(someAddress).deposit.value(100)(); ```