├── best-practices ├── txorigin-attack.png ├── gas-consumption.md ├── assert-require-revert.md ├── avoiding-floating-pragma.md ├── rounding-errors-with-division.md ├── Readme.md ├── timestamp-can-be-manipulated.md ├── be-careful-with-loops.md ├── avoid-txorigin-for-auth.md ├── careful-with-external-calls.md └── avoid-sharing-secret-onchain.md ├── known-attack-patterns ├── reentrency-attack.png ├── tkn-front-running-attack.png ├── Readme.md ├── ether-sent-forcibly.md ├── integer-overflow-underflow.md ├── reentrancy-attacks.md ├── replay-attack.md └── front-running-attacks.md ├── Readme.md ├── design-patterns ├── Readme.md ├── creational │ └── Readme.md ├── life-cycle │ └── Readme.md ├── gas-economic │ └── Readme.md ├── security │ └── Readme.md └── behavioral │ └── Readme.md └── code-quality └── Readme.md /best-practices/txorigin-attack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wissalHaji/solidity-coding-advices/HEAD/best-practices/txorigin-attack.png -------------------------------------------------------------------------------- /known-attack-patterns/reentrency-attack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wissalHaji/solidity-coding-advices/HEAD/known-attack-patterns/reentrency-attack.png -------------------------------------------------------------------------------- /known-attack-patterns/tkn-front-running-attack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wissalHaji/solidity-coding-advices/HEAD/known-attack-patterns/tkn-front-running-attack.png -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | This repo is a copy of some chapters from the book [Mastering Blockchain Programming with Solidity](https://www.amazon.fr/Mastering-Blockchain-Programming-Solidity-production-ready/dp/1839218266). 2 | 3 | The content of this repo includes solidity best practices, code quality tools, design patterns and some known attack patterns. 4 | 5 | - [Best practices](best-practices/Readme.md) 6 | - [Code quality tools](code-quality/Readme.md) 7 | - [Design Patterns](design-patterns/Readme.md) 8 | - [Known attack patterns](known-attack-patterns/Readme.md) 9 | -------------------------------------------------------------------------------- /best-practices/gas-consumption.md: -------------------------------------------------------------------------------- 1 | # Gas consumption 2 | 3 | In the Ethereum blockchain, every contract deployment and transaction consumes gas. The gas is paid in ether and has an economic value. When you deploy a contract, the compiled code is sent to the blockchain. The bigger the contract code is, the more gas units it consumes when deployed. It is recommended that the contract should be compiled with optimization flag enabled. Enabling optimization might optimize the code size and consume less gas units when deployed. Sometimes, the optimized contract also consumes less gas units when their function is called. 4 | 5 | You can also look at the Economic patterns section 6 | -------------------------------------------------------------------------------- /design-patterns/Readme.md: -------------------------------------------------------------------------------- 1 | # Solidity Design Patterns 2 | 3 | The Solidity language is a contract-oriented programming language. There are many constructs required for contract interaction. Also, due to the limitations of the language, few data structure-specific design patterns are used. 4 | 5 | In this chapter, you will learn about the different design patterns, that are grouped into different categories based on their usage. These categories are as follows: 6 | 7 | - [Security design patterns](security/Readme.md) 8 | - [Creational patterns](creational/Readme.md) 9 | - [Behavioral patterns](behavioral/Readme.md) 10 | - [Economic patterns](gas-economic/Readme.md) 11 | - [Life cycle patterns](life-cycle/Readme.md) 12 | 13 | Out of these categories, some of the design patterns that are mostly used in Solidity contracts are listed here: 14 | 15 | - The withdrawal pattern to withdraw ether from the contract 16 | - The factory contract pattern to create new contracts 17 | - The state machine pattern to transition a contract from different states 18 | - The tight variable packing to reduce gas consumption when using structs 19 | -------------------------------------------------------------------------------- /best-practices/assert-require-revert.md: -------------------------------------------------------------------------------- 1 | # Using assert(), require(), and revert() properly 2 | 3 | In Solidity, three functions are provided by the language to check for the invariant, validations, and to fail the transaction. These functions are as follows: 4 | 5 | - assert(): The assert() function should be used when you want to check for invariants in the code. When any invariant is incorrect, the code execution stops, transaction fails, and contract state changes are reverted. This function should only be used for invariant checking. It should not be used for input validation or pre-condition checking. 6 | - require(): The require() function should be used when you want to validate the arguments provided to the function. It is also used to check for the valid conditions and variable values to be in an expected state. If the validation fails, the transaction also fails, and the contract state changes are reverted. 7 | - revert(): The revert() function should be used to simply fail the transaction. Ensure that the revert() function is called under some certain conditions. Once this function is called, the transaction fails, and the contract state changes are reverted. This should be used when you cannot use the require() function. 8 | -------------------------------------------------------------------------------- /known-attack-patterns/Readme.md: -------------------------------------------------------------------------------- 1 | # Known attack patterns 2 | 3 | On the Ethereum blockchain, many hacks occurred between the years 2017 and 2018, and they continue happening because of buggy contract code. In the year 2018 only, more than $1 billion worth of ether and tokens got stolen from Ethereum smart contracts due to vulnerabilities present in the code that attackers exploited. These hacks happened because of bad coding practices and a lack of testing of the contracts. 4 | 5 | Looking at how those hacks happened, there have been many attack patterns that have been identified. It is the developer's responsibility to check their code for all of these known attack patterns. If these attack patterns are not prevented, there could be a loss of money (ether/tokens) or the attacker could enforce unintended transactions on the contracts. 6 | 7 | Always keep yourself updated with the new features added in the Ethereum hard-forks or soft-forks. These new features could help you reduce the attack surface. However, some new features in Ethereum could allow more new attack patterns. As and when you learn about a new attack pattern, check your contracts and ensure that your contracts do not form these patterns. 8 | 9 | Let's look at some of the well-known attack patterns. 10 | 11 | - [Front running attacks](front-running-attacks.md) 12 | - [Reentrancy attacks](reentrancy-attacks.md) 13 | - [Replay attack](replay-attack.md) 14 | - [Integer overflow and underflow attacks](integer-overflow-underflow.md) 15 | - [Ether can be sent forcibly to a contract](ether-sent-forcibly.md) 16 | -------------------------------------------------------------------------------- /best-practices/avoiding-floating-pragma.md: -------------------------------------------------------------------------------- 1 | # Avoiding floating pragma 2 | 3 | The first line of a Solidity contract always starts with defining the pragma solidity version. This indicates the Solidity compiler version, using which the code should be compiled. The pragma is defined as follows: 4 | 5 | ``` 6 | // Bad Practice 7 | pragma solidity ^0.5.0; 8 | ``` 9 | 10 | The preceding code signifies that the code should be compiled with any Solidity version starting from 0.5.0 to 0.5.x because the version starts with a ^ (caret sign). For example, if the latest compiler version of Solidity available is 0.5.8, then the contract can be compiled with any compiler version between 0.5.0 and 0.5.8. 11 | 12 | It is always recommended that pragma should be fixed to the version that you are intending to deploy your contracts with. The contracts should be deployed with the version that they have been tested with. Using floating pragma does not ensure that the contracts will be deployed with the same version. 13 | 14 | It is possible that if you used floating pragma while deploying your contracts, then the most recent compiler version will be picked. The most recent version of compiler has higher chances of having bugs in it. Hence, it is better to keep your contract to a fixed compiler version. 15 | 16 | Fixed pragma is defined as follows: 17 | 18 | ``` 19 | // Good Practice 20 | pragma solidity 0.5.0; 21 | ``` 22 | 23 | Using the preceding line, you are instructing the compiler to compile the contract only with the 0.5.0 Solidity compiler. The fixed pragma also prevent contracts from not using the very latest version of the compiler. As the latest version of the compiler might have some unknown bugs. 24 | -------------------------------------------------------------------------------- /best-practices/rounding-errors-with-division.md: -------------------------------------------------------------------------------- 1 | # Rounding errors with division 2 | 3 | In the Solidity language, there is no official support for floating-point numbers. In the future, there will be support for floating-point numbers. Developers have to use unsigned uintX or signed intX integers only for their calculations. Hence, if any division operation is performed, the result of that calculation might have rounding errors. The result is always rounded down to the nearest integer. 4 | 5 | Here is an example in the following code: 6 | 7 | ``` 8 | //Bad Practice 9 | uint result = 5 / 2; 10 | ``` 11 | 12 | The preceding code would set value 2 in the result variable, as 2.5 rounded down to the nearest integer. 13 | 14 | These rounding errors could cause problems when you are calculating some values that affect tokens, bonuses, or dividends. Hence, a developer must know that the rounding errors would be possible in the calculations and must ensure the best way possible to mitigate these issues: 15 | 16 | ``` 17 | uint bonusTokens = balances[msg.sender] * dividendAmount / totalSupply; 18 | ``` 19 | 20 | As you can see from the previous code, there could be some rounding errors present in the bonusTokens calculation. 21 | 22 | To prevent rounding errors to a certain extent, you should do the multiplication (if multiplication exists) of the values first and then only perform the division operation, as this would have less rounding errors. Otherwise, performing calculations on variables that have some rounding errors already could cause more issues in the final result: 23 | 24 | ``` 25 | //Bad Practice 26 | uint intermediateResult = 5 / 2; 27 | uint finalResult = 10 * intermediateResult; 28 | 29 | //Good Practice 30 | uint finalResult = (10 * 5) / 2; 31 | ``` 32 | 33 | As you can see, the first finalResult variable will be assigned with a value of 20. However, the second finalResult variable will be assigned with a value of 25 as we performed multiplication before the division operation. 34 | -------------------------------------------------------------------------------- /best-practices/Readme.md: -------------------------------------------------------------------------------- 1 | # Smart contracts best practices 2 | 3 | In Solidity, there are many global variables and constructs available for developers to use. However, there are some limitations you must know about, otherwise, it could harm your contracts in production. 4 | 5 | If your contract has bugs or incorrect architecture, which allows an attacker to gain unauthorized control over your contracts, an attacker can steal funds from your contracts, or they can perform unintended operations on contracts, which, in turn, can harm you or your users economically. There have been many attacks in past that have allowed an attacker to gain full control over a contract and steal millions of dollars worth of ether. One such example is the Parity MultiSig wallet hack, in which more than 150,000 ETH was stolen in July 2017. 6 | 7 | The Ethereum blockchain is slow in terms of transaction execution. This slowness also creates some problems related to the transaction reordering. Also, the Ethereum blockchain is public, meaning that any transaction data that you passed in is visible to everyone. Hence, you will have to keep those things in mind when you design your contracts. 8 | 9 | While writing the smart contracts in Solidity as a developer, you will have to be aware of a few things and constructs. Let's discuss the best practices that you will have to be aware of. 10 | 11 | - [Avoiding floating pragma](avoiding-floating-pragma.md) 12 | - [Avoid sharing a secret on-chain](avoid-sharing-secret-onchain.md) 13 | - [Be careful while using loops](be-careful-with-loops) 14 | - [Avoid using tx.origin for authorization](avoid-txorigin-for-auth.md) 15 | - [The timestamp can be manipulated by miners](timestamp-can-be-manipulated.md) 16 | - [Carefully making external function calls](careful-with-external-calls.md) 17 | - [Rounding errors with division](rounding-errors-with-division.md) 18 | - [Using assert(), require() and revert() properly](assert-require-revert.md) 19 | - [Gas consumption](gas-consumption.md) 20 | -------------------------------------------------------------------------------- /best-practices/timestamp-can-be-manipulated.md: -------------------------------------------------------------------------------- 1 | # The timestamp can be manipulated by miners 2 | 3 | In the Solidity language, there are two globally available variables: block.timestamp and now. Both are aliases and are used to get the timestamp when the block is added to the blockchain. The timestamp is in Unix epoch time in seconds. This timestamp is set by the miner when solving the Proof-of-Work (PoW) puzzle. The timestamp of the new block must be greater than the timestamp of the previous block. However, the miner can manipulate the timestamp. 4 | 5 | If your contracts need random numbers, you should not use block.timestamp or now, as these can be manipulated by miners. Consider the following example: 6 | 7 | ``` 8 | // Bad Practice 9 | function random() public view returns (uint){ 10 | bytes32 hash = keccak256( 11 | abi.encode(blockhash(block.number), block.timestamp)); 12 | return uint(hash); 13 | } 14 | ``` 15 | 16 | As you can see, the random number generation is using blockhash and block.timestamp. As block.timestamp can be manipulated by miners, they can set it in a certain way so that they can benefit from it. The random number generation from the contract is still not very robust; hence, you should not generate random numbers in contracts. 17 | 18 | ## The 15-second blocktime rule 19 | 20 | According to the yellow paper of Ethereum, the timestamp for the new block must be greater than the previous block; otherwise, the block will be rejected. The timestamp can be manipulated by the miners using the client software they are running to mine the blocks. There are two Ethereum client software used mostly, and these are Geth and Parity clients. Using their software code and algorithms, these two clients maintain the 15-second rule such that the timestamp difference between the two blocks should not be more than 15 seconds. Otherwise, the client software rejects the block. 21 | 22 | Hence, if you are using block.timestamp or now in your contract code, you need to ensure that you are not performing any processes that would require less than 15 seconds. 23 | -------------------------------------------------------------------------------- /known-attack-patterns/ether-sent-forcibly.md: -------------------------------------------------------------------------------- 1 | # Ether can be sent forcibly to a contract 2 | 3 | While writing a contract, you can define a payable fallback function to accept ether in your contract, as follows: 4 | 5 | ``` 6 | function() external payable { 7 | } 8 | ``` 9 | 10 | If this fallback function is not present in a contract and it does not have the payable modifier for any function, then your contract is not meant to receive ether. 11 | 12 | However, there is still a possible way to send ether to a contract that does not accept ether. This is possible via a selfdestruct function call: 13 | 14 | - Let's assume there is a contract x that has some ether present in it. 15 | - Also, there is a contract y. 16 | - Contract x calls the selfdestruct(address_Of_ContractY) function. 17 | - This process sends all ether present in contract x to contract y, even if contract y neither has a fallback function nor a payable function. 18 | 19 | The code snippet from contract x is as follows: 20 | 21 | ``` 22 | function kill(address _contractY_addr) external onlyOwner { 23 | selfdestruct(_contractY_addr); 24 | } 25 | ``` 26 | 27 | The preceding is the code present in contract x; once the kill() function is called by the owner of the contract x, all the ether present in this contract will be sent to contract y. Even If contract y has a payable fallback function defined; in this case of forcible sending of ether, it will not be executed, however, the ether balance of contract y would increase silently. 28 | 29 | By using the previous approach, an attacker could affect the behavior of your contract in certain situations: if your contracts are only accepting ether from authorized sources and via either fallback or payable functions, and if your contract code contains some decision logic using address(this).balance (this gives the current ether balance of the contract). Then, an attacker can influence the decision logic, as he would be able to manipulate the contract's ether balance using an unauthorized method. 30 | 31 | ## Prevention and precaution 32 | 33 | At the moment, there is no possible way to prevent forceful ether sending from happening. 34 | 35 | However, the developer should caution that you should not assume any specific amount of ether in the contract and write the contract logic. If you do so, an attacker can attack and might lock your contract by sending some ether to your contract forcefully. For example, you should not use address(this).balance in your code to check the contract ether balance and compare it with any specific value. 36 | -------------------------------------------------------------------------------- /code-quality/Readme.md: -------------------------------------------------------------------------------- 1 | # Taking Advantage of Code Quality Tools 2 | 3 | Code quality is one of the important aspects of writing applications. Good quality code always tends to have fewer bugs and problems when deployed in production. To maintain and improve code quality, there are always some tools specific to the language you are coding with. Similarly, there are some tools for Solidity as well. 4 | 5 | In this chapter, we are going to learn about some of the tools that are used while developing Solidity contracts. There are many open source tools available for the Solidity language, and these include code quality tools such as contract graph generators, linters, and code coverage tools. Using these contract graph generators, you can view how the contracts are linked together; using the linters, you can fix possible bugs, errors, and stylistic errors; and using the code coverage tools, you can discover which part of the code is well tested and which part is not covered by the test cases. 6 | 7 | ## Using the surya tool 8 | 9 | The surya tool is an open source command-line utility tool that is used to generate a number of graphical and other reports. The tool works by scanning through the Solidity smart contract files and can generate inheritance and function call graphs. It also generates a function-specific report in a tabular format. Using all of these generated graphs and reports, a developer can understand smart contract architecture and dependencies by doing a manual inspection. 10 | 11 | Let's start by installing the surya tool on your machine. 12 | 13 | Installing surya 14 | 15 | To install the surya utility tool on your machine, run the following command: 16 | 17 | `npm install -g surya` 18 | 19 | ## Understanding Solidity linters 20 | 21 | Linters are the utility tools that analyze the given source code and report programming errors, bugs, and stylistic errors. For the Solidity language, there are some linter tools available that a developer can use to improve the quality of their Solidity contracts. These tools report the known pattern of errors or bugs and also check any security flaws that could be checked by the developers to ensure the safety of the contract. 22 | 23 | However, these linter tools should be used along with the compiler's reported warnings. Because the compiler itself reports many warnings and informs the developer about the best language guidelines, it also suggests using the improved language syntax to reduce the security bug. You should bear in mind that the compiler warnings are not sufficient to have good quality code. You can also automate and write a script to compile the code and run linters on it after successful compilation. 24 | 25 | For the Solidity language, there are two commonly used linter tools available; these are solhint and solium (also known as ethlint). 26 | 27 | ## The solidity-coverage tool 28 | 29 | Code coverage tools are used to determine which part of the code is covered and tested by the different test cases and which part is not tested. These tools offer an insightful view of the code and its related test cases. Once developers write the test cases for their Solidity project, they can use the coverage tools to find their code coverage. The more the code is covered with test cases, the lower the probability that you will find any bugs in the code in the future. 30 | 31 | For Solidity, there is an open source tool called solidity-coverage. 32 | -------------------------------------------------------------------------------- /design-patterns/creational/Readme.md: -------------------------------------------------------------------------------- 1 | # Creational patterns 2 | 3 | Creational patterns are used to create different contracts as and when needed. There are some situations when a new contract creation is required from within a contract. The factory contract pattern is the most-used design pattern for creating new contracts. The creation pattern also helps a contract to only create a predefined contract. Let's look at the factory contract pattern. 4 | 5 | ## Factory contract pattern 6 | 7 | The factory contract pattern is used when you want to create a new child contract from a parent contract. The benefit of this pattern is that the contract definition is predefined in the main contract and the new contract is deployed with this predefined code. This protects the new contract code from an attacker, as the code of the contract is already defined. 8 | 9 | In the following example code, we have a LoanMaster contract. This contract has a createLoanRequest() function that can be called by anyone. This further calls the createInstance() function of the LoanFactory contract to deploy a new instance of a Loan contract using new Loan(). Here, the new solidity keyword is used to create and deploy a new instance of the Loan contract and call its constructor with the given arguments. The creator of the Loan contract is assigned as a borrower in the Loan contract, as shown in the following sample code: 10 | 11 | ``` 12 | contract LoanMaster { 13 | address[] public loans; 14 | address public loanFactoryAddress; 15 | 16 | function createLoanRequest(address _token, uint _loanAmount) public { 17 | address loan = LoanFactory(loanFactoryAddress) 18 | .createInstance(msg.sender, _token, _loanAmount); 19 | loans.push(loan); 20 | } 21 | } 22 | 23 | contract LoanFactory { 24 | function createInstance( 25 | address _borrower, 26 | address _token, 27 | uint _loanAmount 28 | ) public returns (address) { 29 | return new Loan(_borrower, _token, _loanAmount); 30 | } 31 | } 32 | 33 | contract Loan { 34 | address token; 35 | address borrower; 36 | uint loanAmount; 37 | 38 | constructor(address _borrower, address _token, uint _loanAmount) public 39 | { 40 | borrower = _borrower; 41 | token = _token; 42 | loanAmount = _loanAmount; 43 | } 44 | 45 | //Other logic of Loan contract 46 | } 47 | ``` 48 | 49 | The LoanFactory contract is deployed separately from the LoanMaster contract. This way, the LoanFactory contract can be used by any of the contracts to create any number of new Loan contracts. In the preceding example, a Loan contract is used between a single borrower and a single lender. 50 | 51 | Let's understand when and where factory contract patterns should be used. 52 | 53 | ### Applicability 54 | 55 | The factory contract pattern should be used in the following cases, when: 56 | 57 | - A new contract is required for each request to be processed. For example, in the case of creating a new loan term between two parties, a master contract can create a new child contract called Loan. This new Loan contract has logic to handle contract terms and conditions along with the funds as well. 58 | - You would need to keep the funds separate in a different contract. 59 | - A separate contract logic should be deployed per request and one or more entities are to be tied together using this newly deployed contract. 60 | -------------------------------------------------------------------------------- /best-practices/be-careful-with-loops.md: -------------------------------------------------------------------------------- 1 | # Be careful while using loops 2 | 3 | You can use loops in two ways as bounded or unbounded loops. If you are performing some operations in contract or just calculating some results, you can use either of the loops. 4 | 5 | You can have loops for any function in the Solidity language. However, if the loop is updating some state variables of a contract, it should be bounded; otherwise, your contract could get stuck if the loop iteration is hitting the block's gas limit. If a loop is consuming more gas than the block's gas limit, that transaction will not be added to the blockchain; in turn, the transaction would revert. Hence, there is a transaction failure. Always consider having bounded loops in which you are updating contract state variables for each iteration. Try to avoid using loops that change contract state variables in the first place. 6 | 7 | You can have unbounded loops for view and pure functions, as these functions are not added into the block; they just read the state from the blockchain when message calls are made to these functions. 8 | 9 | However, if these view or pure functions (containing loops) you are using in other public/external functions, it could block your contract operation because the view or pure functions would consume gas when they are being called from non-pure / non-view functions. Let's look at the following code: 10 | 11 | ``` 12 | contract DividendCalculator is Ownable { 13 | struct Account { 14 | address payable investor; 15 | uint dividend; 16 | } 17 | Account[] investors; 18 | mapping(address => Account) investorsMap; 19 | 20 | modifier onlyInvestor() { 21 | require(msg.sender == investorsMap[msg.sender].investor); 22 | _; 23 | } 24 | 25 | function calculateDividend() public onlyOwner { 26 | //Bad Practice 27 | for(uint i = 0; i < investors.length; i++) { 28 | uint dividendAmt = calcDividend(investors[i].investor); 29 | investors[i].dividend = dividendAmt; 30 | } 31 | } 32 | 33 | function withdraw() public onlyInvestor { 34 | Account memory account = investorsMap[msg.sender]; 35 | uint dividendAmount = account.dividend; 36 | account.dividend = 0; 37 | account.investor.transfer(dividendAmount); 38 | } 39 | 40 | function calcDividend(address investor) internal returns 41 | (uint){ 42 | //Logic to calculate dividend 43 | } 44 | } 45 | ``` 46 | 47 | As shown in the preceding code, the owner can calculate the dividend amount for each investor. However, in the calculateDividend() function, there is an unbounded loop, which could start failing the transaction because of insufficient gas, once it starts consuming more gas units than the block gas limit. 48 | 49 | To avoid these issues, you must pass in the number of iterations a loop can execute: 50 | 51 | ``` 52 | //Good Practice 53 | function calculateDividend(uint from, uint to) public onlyOwner { 54 | require(from < investors.length); 55 | require(to <= investors.length); 56 | for(uint i = from; i < to; i++) { 57 | uint dividendAmt = calcDividend(investors[i].investor); 58 | investors[i].dividend = dividendAmt; 59 | } 60 | } 61 | ``` 62 | 63 | The preceding code would help the owner of the contract create multiple batches to calculate dividend. This avoids the transaction failure issues related to insufficient gas. 64 | -------------------------------------------------------------------------------- /best-practices/avoid-txorigin-for-auth.md: -------------------------------------------------------------------------------- 1 | # Avoid using tx.origin for authorization 2 | 3 | The msg.sender global variable gives the address of the caller of the function. The tx.origin is also a globally available variable that returns the address of the transaction initiator. For example, using an EOA account; Alice initiates a transaction to Contract-A which further makes a function call to a Contract-B. Then the function present in Contract-B would give the address of the Contract-A when msg.sender is evaluated; however, when tx.origin is evaluated in the same function, it would return the address of Alice's EOA, because Alice is the original transaction initiator. 4 | 5 | The tx.origin method should not be used as authorization for any function. The access control protected using tx.origin can be attacked and would allow an attacker to gain unauthorized access rights. 6 | 7 | In the following code, we have a Vault contract, which keeps the ether of an owner. The owner of the Vault contract can withdraw their ether at any point in time: 8 | 9 | ``` 10 | contract Vault { 11 | address authorized; 12 | 13 | modifier onlyAuthorized() { 14 | // Bad Practice 15 | require(authorized == tx.origin); 16 | _; 17 | } 18 | 19 | function withdraw(address beneficiary) public onlyAuthorized { 20 | beneficiary.transfer(address(this).balance); 21 | } 22 | } 23 | ``` 24 | 25 | An attacker writes the AttackerContract code as follows: 26 | 27 | ``` 28 | contract AttackerContract { 29 | address targetContract; 30 | address attackerWallet; 31 | 32 | function () external payable { 33 | Vault(targetContract).withdraw(attackerWallet); 34 | } 35 | } 36 | ``` 37 | 38 | Here is the diagram explaining how an attacker could attack his victim: 39 | tx.origin attack 40 | 41 | Attacker steals ETH from Victim's contract via tx.origin 42 | 43 | In the preceding diagram, we have shown how an attacker attacked on the Vault contract which is using tx.origin in the onlyAuthorized modifier, in order to check the authorization of the function caller. The following actions take place in this scenario: 44 | 45 | 1. An attacker will create an AttackerContract contract and deploy it. Somehow, an attacker would ask the original owner of the Vault contract to send some ether to the AttackerContract contract. 46 | 2. Once the original owner sends the ether to AttackerContract, transaction calls the Vault.withdraw() function. Then, it would check that tx.origin is the authorized person of this contract, execute the withdraw() in the Vault contract, and send all the ether present in the Vault contract to the attacker's wallet. 47 | 48 | We have discussed an attack in which there was a Victim (user) and two contracts involved. However, this is not the only case where this kind of attack is possible. There could be many more contracts in between as well. Also, you need to know that when you are using an external library contract, all the function calls are made using delegate calls to the library functions. 49 | 50 | ## Preventing an attack 51 | 52 | You should not use tx.origin in your contract to check for the authorization. Always use msg.sender to check the authorization of the function calls: 53 | 54 | ``` 55 | modifier onlyAuthorized() { 56 | //Good Practice 57 | require(authorized == msg.sender); 58 | _; 59 | } 60 | ``` 61 | 62 | In the preceding code, we are using msg.sender instead of tx.origin. This fixes the issue, and an attacker would not be able to perform the attack because msg.sender always returns the address of the previous caller in the call stack. In the previous attack scenario, msg.sender would return the address of AttackerContract; hence, authorization fails, and funds would not be sent to the attacker. 63 | -------------------------------------------------------------------------------- /known-attack-patterns/integer-overflow-underflow.md: -------------------------------------------------------------------------------- 1 | # Integer overflow and underflow attacks 2 | 3 | In Solidity, there are data types that represent fixed-size integers. For example, all uint8 datatype from uint8, uint16, and moving up to uint256, increasing the bit value by 8 each time. Each type has a different limit to store an integer. For example, a variable of type uint8 can store values from 0 to 28-1 (0 to 255). 4 | 5 | Similarly, int8 up to int256 (increasing the bit value by 8 each time) are also prone to integer overflow or underflow attacks. 6 | 7 | When a value of the variable reaches the upper limit and further increases, it will cause integer overflow and the value goes back to zero. Also, when the value of the variable reaches the lower limit and further decreases, it will cause integer underflow, and the value goes back to a maximum value of the data type. 8 | 9 | For example, you have an int8 variable in the contract. The value assigned to it is 255 (the maximum value an int8 variable can hold). Now, you increase the value of this variable just by 1, either using arithmetic operators such as +, +=, or ++. The new value of the variable would be 0 (the lowest value an int8 variable can hold) as it has caused integer overflow. 10 | 11 | The values of these variables are increased or decreased using some operators. These operators are as follows: 12 | 13 | - Arithmetic operators: +, -, and \* 14 | - Arithmetic and assignment operators: +=, -=, and \*= 15 | - Pre and post, increment, and decrement operators: ++ and -- 16 | 17 | You need to be cautious when using the preceding operators for arithmetic operations: 18 | 19 | ``` 20 | // Bad Practice 21 | function transfer(address _to, uint256 _value) public { 22 | balanceOf[msg.sender] -= _value; 23 | balanceOf[_to] += _value; 24 | } 25 | ``` 26 | 27 | The preceding transfer() function is prone to both integer overflow and integer underflow attacks. Because there is no check present that ensures that the \_value variable can have a valid value that would not cause integer overflow or integer underflow. An attacker can pass a high value for the \_value argument so that the balance of msg.sender is increased to the maximum of uint256; that way, they can perform an integer underflow attack. Similarly, they can decrease the balance of \_to to zero. 28 | 29 | One way to avoid integer overflow or underflow attacks in Solidity code is to check for the boundaries of the data type before assigning new values; however, this can be dangerous if any condition is missed. Doing this requires extra care and attention while writing code: 30 | 31 | ``` 32 | // Good Practice, but not the best as more code is required to prevent 33 | // from integer overflow and underflow attacks 34 | function transfer(address _to, uint256 _value) public { 35 | require(balanceOf[msg.sender] >= _value); 36 | 37 | balanceOf[msg.sender] -= _value; 38 | balanceOf[_to] += _value; 39 | } 40 | ``` 41 | 42 | Instead, you can use the SafeMath library provided by the OpenZeppelin libraries. This library reverts the transaction when integer overflow or underflow happens: 43 | 44 | ``` 45 | import "openzeppelin-solidity/contracts/math/SafeMath.sol"; 46 | 47 | contract ERC20 { 48 | using SafeMath for uint; 49 | mapping(address => uint) balanceOf; 50 | 51 | // Good Practice 52 | function transfer(address _to, uint256 _value) public { 53 | balanceOf[msg.sender] = balanceOf[msg.sender].sub(_value); 54 | balanceOf[_to] = balanceOf[_to].add(_value); 55 | } 56 | } 57 | ``` 58 | 59 | In the preceding code, we are using the SafeMath library; when using the sub() or add() library functions, we do not even need to check for other conditions as the transaction would revert automatically when the integer overflow or underflow happens. 60 | 61 | Note that the SafeMath library is for the uint256 data type only. For the int256 data type, you can use the SignedSafeMath library present in the OpenZeppelin libraries. You can refer Chapter 9, Deep Dive Into the OpenZeppelin Library, Math-related libraries, for more details on these library files. 62 | -------------------------------------------------------------------------------- /design-patterns/life-cycle/Readme.md: -------------------------------------------------------------------------------- 1 | # Life cycle patterns 2 | 3 | A Solidity contract is created either by deploying a new contract or by creating from within a contract. Apart from these, a contract and its functions can follow a different life cycle. A Solidity contract can also be destroyed by calling the selfdestruct function. Once a contract is destroyed, it cannot be recreated on the same address. 4 | 5 | Similarly, using the timestamp's global variables and time units, contract states can also be moved. It is also possible to allow the contract functions to be called based on these timestamps. Let's look into the life cycle design patterns. 6 | 7 | ## Mortal pattern 8 | 9 | The mortal pattern allows a contract to be destroyed from the Ethereum blockchain. As you know, a Solidity contract can be destroyed using a selfdestruct() function call in the contract. You can have this function call in your contract to allow it to be destroyed once the contract job is over. Once a contract is destroyed, the contract states would not remain on the blockchain, and if there are any ethers present in the contract, it would be sent to an address passed to the selfdestruct() function as argument. 10 | 11 | As you can see in the following sample code, there is a kill() function. Only the owner of the contract can call this function: 12 | 13 | import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; 14 | 15 | ``` 16 | contract Mortal is Ownable { 17 | 18 | //... 19 | //Contract code here 20 | //... 21 | 22 | function kill() external onlyOwner { 23 | selfdestruct(owner()); 24 | } 25 | } 26 | ``` 27 | 28 | Once the owner of the contract calls the kill() function, the contract is destroyed from the Ethereum blockchain and any ether present in the contract is sent to the owner. 29 | The mortal pattern is very dangerous when used in the contract. You should not use this pattern in the first place. 30 | 31 | Let's understand when and where the mortal pattern should be used. 32 | 33 | ### Applicability 34 | 35 | The mortal pattern should be used in the following cases, when: 36 | 37 | - You do not want a contract to be present on the blockchain once its job is finished 38 | - You want the ether held on the contract to be sent to the owner and the contract is not required further 39 | - You do not need the contract state data after the contract reaches a specific state 40 | 41 | ## Auto deprecate pattern 42 | 43 | The auto deprecate pattern allows time-based access to certain function calls. In Solidity, using the block.timestamp and now calls, you can get the time of the block when it is mined. Using this time, you can allow or restrict certain function calls in Solidity. There are also some globally available time units present in the Solidity language that you can use. These time units are seconds, minutes, hours, days, weeks, and years. You can use these time units to calculate the Unix epoch time in the past or in the future. 44 | 45 | In the following code, the contribution() function should only be called in a specified duration of time: 46 | 47 | ``` 48 | contract AutoDeprecate { 49 | 50 | uint startTime; 51 | uint endTime; 52 | 53 | modifier whenOpen() { 54 | require(now > startTime && now <= endTime); 55 | _; 56 | } 57 | 58 | constructor(uint _startTime, uint _endTime) public { 59 | require(_startTime > now); 60 | require(_endTime > _startTime); 61 | require(_endTime > _startTime + 1 weeks); 62 | 63 | startTime = _startTime; 64 | endTime = _endTime; 65 | } 66 | 67 | function contribute() public payable whenOpen { 68 | //Contribution code here 69 | } 70 | 71 | function isContributionOpen() public view returns(bool) { 72 | return now > startTime && now <= endTime; 73 | } 74 | } 75 | ``` 76 | 77 | The contribution() function uses the whenOpen modifier. The whenOpen modifier only allows the function call between the startTime and endTime variables. Both of these times are set from the constructor of the contract and the duration between these two times must be equal to or greater than a week. 78 | 79 | Let's look at when and where auto deprecate patterns should be used. 80 | 81 | ### Applicability 82 | 83 | The auto deprecate design pattern should be used in the following cases, when: 84 | 85 | - You want to allow or restrict a function call before or after a specified time 86 | - You want to allow or restrict a function call for a specified duration of time 87 | - Auto-expire a contract, which would not allow any function calls after the expiry time 88 | -------------------------------------------------------------------------------- /best-practices/careful-with-external-calls.md: -------------------------------------------------------------------------------- 1 | # Carefully making external function calls 2 | 3 | The Solidity smart contracts do have a size limit for deployment. A contract that consumes less than 8 million gas at the time of deployment can be deployed on the Ethereum blockchain at the moment. In the future, this limit of 8 million gas could be increased. When your contracts are big enough and cannot be deployed in a single block, they need to be further divided into multiple small contracts. You can break a big contract into multiple small contracts and libraries and interconnect these contracts via function calls with the required authorization. 4 | 5 | Not only that, if your contracts needed to communicate with some external service, you would need to make external function calls to external contracts. For example, the Oraclize service is a third-party service that provides APIs to fetch data from the internet and lets you use it in the blockchain. The Oraclize service has exposed some external function calls, which your contracts can call and use. 6 | 7 | When you need to call external functions, the developer must know under which category the target contract belongs to, such as the following: 8 | 9 | - Trusted contracts: A contract that is deployed and managed by you is known as a trusted contract. External function calls to trusted contracts often not create any issues, as they are known. 10 | - Untrusted contracts: A contract that is deployed and managed by another entity, for example, Oraclize contracts. These are known as untrusted contracts. External function calls to these untrusted contracts might have some security implications in future if their contracts are attacked. 11 | 12 | However, the definition of an untrusted contract is up to the developers and the project; if they believe that certain external service contracts can be treated as trusted contracts, they can use it. If they are not sure about the contract code or the third-party contract, then they can classify that contract as an untrusted contract. 13 | 14 | To give an example, if your contracts require integration with external contracts, such as KyberNetwork's decentralized exchange, you can use them as KyberNetwork contracts are security audited and have been used by many people for a considerable amount of time. You can take KyberNetwork contracts as trusted. If you are unsure about some external contract and the code is not open, then you can treat these contracts as untrusted contracts. However, once again this is your decision when architecting the design of your contracts and integration with external services. 15 | 16 | Let's discuss some of the things that should be avoided when making external function calls from a contract. 17 | 18 | ## Avoid dependency on untrusted external calls 19 | 20 | As we have discussed, there are some contracts or services that are managed by an external third party. The risk in calling an external function on these services is very high. Our external function calls are dependent on their contract and code, and hence it might be possible for these external services to inject malicious code; if executed, your contracts would behave unexpectedly. It is always recommended to have fewer untrusted external function calls. 21 | 22 | Ensure that enough due diligence is done while choosing an external contract for integration with your contracts. 23 | 24 | ## Avoid using delegatecall to untrusted contract code 25 | 26 | By using the delegatecall function present in the contract, you can refer some code from another contract and execute it on the current contract context. Library functions are delegate-called to the current contract execution. 27 | 28 | When the target contract address is untrusted, and/or when you are not sure about the code, you should not make delegatecall to these untrusted contracts. These untrusted contracts can perform malicious operations on your contracts as follows: 29 | 30 | ``` 31 | function _delegate(address _target) internal { 32 | // Bad Practice 33 | _target.delegatecall(bytes4(keccak256("externalCall()"))); 34 | } 35 | ``` 36 | 37 | As you can see from the preceding code, although the \_delegate function is internal, it still takes the \_target argument. If the \_target contract address is an untrusted contract, it can perform any arbitrary code execution on your contract. If the target contract is killed via selfdestruct, the external call to the function will always fail, and if there is any dependency of your contract on that target contract, your contract would stuck forever. 38 | 39 | To avoid such untrusted calls, only use trusted contract addresses to perform the delegatecall operation. Also, do not allow users to pass in the \_target contract address. 40 | -------------------------------------------------------------------------------- /known-attack-patterns/reentrancy-attacks.md: -------------------------------------------------------------------------------- 1 | # Reentrancy attacks 2 | 3 | Many hacks in the past have used this technique. In this attack technique, an attacker deploys a new contract and calls a specific function on the target contract. The call sends ether to the attacker's contract, and their contract makes a function call to the target contract again. This process continues in a loop until all the ether or funds from the target contract is drained in the attacker's contract. 4 | 5 | Let's look at an example where a reentrancy attack is possible: 6 | 7 | ``` 8 | //Bad Practice 9 | function withdraw() public { 10 | uint amount = balances[msg.sender]; 11 | msg.sender.transfer(amount); 12 | balances[msg.sender] = 0; 13 | } 14 | ``` 15 | 16 | In the preceding code, using the withdraw() function, a user can withdraw their ether balance, which they have deposited to this contract previously. As you can see in the code, it reads the user's balance and sends that amount of ether to the function caller, and, at the end, it resets the balance of that function caller. As we learned previously, in Solidity, you can write a fallback function that can receive ether and execute some code. An attacker can deploy a contract, in which they will add a fallback function, as follows: 17 | 18 | ``` 19 | //Code used by an Attacker 20 | address attackedAddress = 0x1234; 21 | 22 | function attack() public onlyOwner { 23 | attackedAddress.withdraw(); 24 | } 25 | 26 | function() external payable { 27 | while(attackedAddress.balance > 0) { 28 | attackedAddress.withdraw(); 29 | } 30 | } 31 | ``` 32 | 33 | In the preceding code attackedAddress value is the address of the contract (which contains ether) on which an attack will be performed. An attacker will deploy this contract and initiate attack to a target contract via the attack() function: 34 | reentrancy attack 35 | 36 | Reentrancy attack by an attacker 37 | 38 | The preceding diagram shows how an attacker could exploit reentrancy vulnerability present in the Target Contract. Let's look at the transaction flow shown in the preceding diagram: 39 | 40 | Lets assume the following is the initial state of the contract: 41 | 42 | - Target Contract has 10 ETH present in it. 43 | - Attacker's Contract has not deposited any ETH to Target Contract yet. It means the attacker's contract, balance[msg.sender], is 0 in Target Contract. 44 | 45 | Transactions are executed in the following order: 46 | 47 | 1. The attacker deploys his contract called an Attacker's Contract. He also deposits 1 ETH into his deployed contract. This transaction is shown as (1) in the preceding diagram. 48 | 49 | 2. The attacker calls the attack() function (transaction (2) shown in the diagram) on his deployed contract and the following internal transactions are executed: 50 | 51 | 1. The deposit() function call deposits 1 ether to Target Contract. This updates the Attacker's Contract balance[msg.sender] balance to 1 ether. It further calls the withdraw() function in the Target Contract. This internal transaction is shown as (2.1) in the preceding diagram. 52 | 2. The withdraw() function present in Target Contract sends 1 ether to Attacker's Contract via the msg.sender.transfer(amount) function call. This, in turn, triggers the fallback function of Attacker's Contract. This transaction is shown as (2.2) in the preceding diagram. 53 | 3. The fallback function checks that Target Contract still has some ether balance in it. If it has balance left, then make a call to the withdraw() function in the Target Contract. This transaction is shown as (2.3) in the preceding diagram. 54 | 55 | 3. The preceding process of internal transactions (2.2) and (2.3) continues until Target Contract's ether balance is not empty. 56 | 4. After executing (2.2) and (2.3) 11 times, transaction (2) would complete and the balance of Attacker's Contract would be 11 ether, and the balance of Target Contract would be 0 ether. 57 | 58 | As you can see using the above reentrancy attack an attacker was able to drain the target contract. The conditions and loop settings might vary according to the code of the attacker's contract and the target contract. 59 | 60 | Let's look at the technique to prevent a reentrancy attack. 61 | 62 | ## Preventing a reentrancy attack 63 | 64 | To prevent a reentrancy attack, the state of the variables should be updated first, and then ether should be sent to a user's account as follows: 65 | 66 | ``` 67 | // Good Practice 68 | function withdraw() public { 69 | uint amount = balances[msg.sender]; 70 | balances[msg.sender] = 0; 71 | msg.sender.transfer(amount); 72 | } 73 | ``` 74 | 75 | In the preceding code, we are updating the balance of the user's account to 0 (zero), and then only sending the ether to the user. 76 | 77 | Remember to always update the relevant state variables first and then only transfer ether at the last step. 78 | -------------------------------------------------------------------------------- /best-practices/avoid-sharing-secret-onchain.md: -------------------------------------------------------------------------------- 1 | # Avoid sharing a secret on-chain 2 | 3 | Ethereum is a public blockchain; hence, all the transaction data is visible to everyone. To execute a function on a contract, a user has to sign the function data from their EOA and send it to the Ethereum blockchain. In this process, the signed data contains the first four bytes of the function signature followed by the function arguments. This data is visible, and anyone can see the function definition as well, if the code of the contract is published on the block explorer. 4 | 5 | If you have a contract that requires confidential data to be sent, it would be visible to everyone, and would not remain private when a transaction is initiated. As the Ethereum blockchain processes transactions slowly, you can see the transaction data and can initiate another transaction. For example, in the game Rock-Paper-Scissors, two players each select one of three options at random, and one wins the game. But if player 2 knows the option chosen by player 1, then player 2 can select the right option so that he/she wins the game all the time: 6 | 7 | ``` 8 | contract RockPaperScissor 9 | { 10 | enum Choice {NONE, ROCK, PAPER, SCISSOR} 11 | 12 | struct PlayerChoice { 13 | address player; 14 | Choice choice; 15 | } 16 | 17 | PlayerChoice[2] players; 18 | 19 | function registerPlayer() public { 20 | if(players[0].player == address(0)) 21 | players[0].player = msg.sender; 22 | 23 | if(players[1].player == address(0)) 24 | players[1].player = msg.sender; 25 | 26 | revert("All players registered"); 27 | } 28 | 29 | function play(Choice _choice) public { 30 | uint index = validateAndfindPlayerIndex(); 31 | players[index].choice = _choice; 32 | } 33 | 34 | function checkWinner() public { 35 | //Code to check winner and reward 36 | } 37 | 38 | function validateAndfindPlayerIndex() internal returns (uint) { 39 | if( 40 | players[0].player == msg.sender && 41 | players[0].choice == Choice.NONE 42 | ) return 0; 43 | 44 | if( 45 | players[1].player == msg.sender && 46 | players[1].choice == Choice.NONE 47 | ) return 1; 48 | 49 | revert("Invalid call"); 50 | } 51 | } 52 | ``` 53 | 54 | As you can see in the preceding sample code of the RockPaperScissor contract, when the play() function is called by player 1, their choice is published on the chain, and player 2 can see player 1's choice. Now player 2 can select a choice so that they always win the game. 55 | 56 | To overcome this problem, you can use the commit-and-reveal scheme, in which all the players first share a secret hash, and, once all the players have submitted the secret hash, they all reveal their secret by sharing the salt in the reveal transaction. 57 | 58 | ## The commit-and-reveal scheme 59 | 60 | In the commit-and-reveal scheme, first, a hash of the original secret is submitted to the blockchain. This secret hash is recorded and stored on-chain in the contract. Once all the players or parties have submitted their secret hash, they all have to reveal their choice by submitting salt, using which they have generated the secret hash. A salt is like a password; using this an user can generate a secret hash. This secret is generated by combining the data (to be hidden) and salt and taking hash of this combined data. You can use any hashing algorithm to generate hashes. We have used keccak256 hashing algorithm in the sample code 61 | 62 | This way of first committing the secret hash and later revealing it prevents players from sharing their original choice. Let's look at the updated code of RockPaperScissor: 63 | 64 | ``` 65 | contract RockPaperScissor 66 | { 67 | //Rest of the exiting code 68 | 69 | struct PlayerChoice { 70 | address player; 71 | bytes32 commitHash; 72 | Choice choice; 73 | } 74 | 75 | function play(bytes32 _commitHash) public { 76 | uint index = validateAndFindPlayerIndex(); 77 | players[index].commitHash = _commitHash; 78 | } 79 | 80 | function reveal(Choice _choice, bytes32 _salt) public { 81 | require( 82 | players[0].commitHash != 0x0 && 83 | players[1].commitHash != 0x0 84 | ); 85 | uint index = findPlayerIndex(); 86 | require(players[index].commitHash == 87 | getSaltedHash(_choice, _salt)); 88 | players[index].choice = _choice; 89 | } 90 | 91 | function getSaltedHash(Choice _answer, bytes32 _salt) 92 | internal view returns (bytes32) { 93 | return keccak256(abi.encodePacked(address(this), _answer, _salt)); 94 | } 95 | } 96 | ``` 97 | 98 | In the preceding code, using the play() function, a player is submitting his secret commit hash. Once all the players have submitted their commit hashes, each player should call the reveal() function to reveal their choices. 99 | 100 | There are some guidelines you must follow for salt usage: 101 | 102 | - The salt that you have revealed on-chain must not be used again in future transactions. It must be different each time. 103 | - The salt must be strong enough in terms of number of characters used, so that it becomes difficult to brute-force. 104 | - If you have used salt while testing on the testnet chain, you should not use the same salt again on the mainnet chain. 105 | - You must keep you salt stored at secret location until it's revealed. 106 | -------------------------------------------------------------------------------- /known-attack-patterns/replay-attack.md: -------------------------------------------------------------------------------- 1 | # Replay attack 2 | 3 | This is a type of attack in which an attacker is allowed to recall the function of the contract, allowing them to update the state variables. Using these attacks, an attacker can update the state variables or perform some unintended operations multiple times when they should not be allowed. The signature replay attacks are mostly prone to replay attacks. You should ensure that signatures are handled correctly in contracts. Let's discuss the signature replay attack. 4 | 5 | ## Signature replay attacks 6 | 7 | There are some cases when a user signs some data off-chain and the data is given to some other authorized user who will submit the signed data on the contract. This process allows users to perform transactions even when off-chain and later, the confirmation or trade is updated on-chain. For example, in projects such as 0xProject, where trades are matched off-chain by signing the order data and later on, actual trade is updated on-chain. 8 | 9 | Let's look at an example: 10 | 11 | ``` 12 | import "openzeppelin-solidity/contracts/cryptography/ECDSA.sol"; 13 | 14 | contract ReplayAttack { 15 | using ECDSA for bytes32; 16 | 17 | //Bad Practice 18 | function submitRequest( 19 | address _signer, 20 | address _target, 21 | uint _param1, 22 | uint _param2, 23 | bytes memory _signature 24 | ) 25 | public onlyAuthorized 26 | { 27 | 28 | bytes memory input = abi.encode(_target, _param1, _param2); 29 | bytes32 inputHash = keccak256(abi.encodePacked(input)); 30 | inputHash = inputHash.toEthSignedMessageHash(); 31 | address recoveredAddress = inputHash.recover(_signature); 32 | 33 | require(recoveredAddress == _signer); 34 | 35 | //Further action on target address 36 | _target.submitRequest(_param1, _param2); 37 | } 38 | } 39 | ``` 40 | 41 | In the preceding code, a user signs the data related to the submitRequest() function and sends it to an authorized user off-chain; later, the authorized person submits the signature along with the signed data to the submitRequest() function. The function checks the inputs signed by the user themselves; otherwise, the transaction will fail. 42 | 43 | However, the preceding code is prone to signature replay attack because the same signed data can be sent again by the authorized person. Sending this data again, they can perform unintended operations that are expected to be performed only once. 44 | 45 | ## Preventing a signature replay attack 46 | 47 | To prevent a replay attack, you should use the nonce in the signed data. The user should sign the data along with a unique nonce value each time. Also, the nonce should be stored on-chain, to show that the user has previously sent the signature with that nonce: 48 | 49 | ``` 50 | mapping (address => mapping(uint => bool)) nonceUsedMap; 51 | 52 | function submitRequest( 53 | address _signer, 54 | address _target, 55 | uint _param1, 56 | uint _param2, 57 | uint _nonce, 58 | bytes memory _signature 59 | ) 60 | public onlyAuthorized { 61 | 62 | bytes memory input = abi.encode(_target, _param1, _param2, _nonce); 63 | bytes32 inputHash = keccak256(abi.encodePacked(input)); 64 | inputHash = inputHash.toEthSignedMessageHash(); 65 | address recoveredAddress = inputHash.recover(_signature); 66 | 67 | require(recoveredAddress == _signer); 68 | require(nonceUsedMap[_signer][_nonce] == false); 69 | 70 | nonceUsedMap[_signer][_nonce] = true; 71 | 72 | //Further action on target address 73 | _target.submitRequest(_param1, _param2); 74 | } 75 | } 76 | ``` 77 | 78 | As you can see in the preceding code, we have introduced a mapping that takes the address of the signer and the nonce used by the signer to sign the data. The call is executed when the nonce is not used previously. The transaction fails when a nonce is used previously. 79 | 80 | There are other prevention methods you can also use to prevent a signature replay attack, as follows: 81 | 82 | - If there are multiple functions in your contract that accept the exact same type of signed data, in that case, a user signs the data thinking that function A() will be called by an authorized person. However, an authorized person can also call function B(), as both of the functions needed the same type of parameters to be signed. To prevent these types of attacks, you can include the function name in the signed data. Having this, even an authorized person cannot call incorrect functions. To include a function name in the signature data, you could also use msg.sig (this gives us the first four bytes of the function called). 83 | - You can also maintain the incremented sequence of the nonce on-chain in the contract itself. This ensures that the function execution from an authorized person can only be performed in sequence according to the nonce increment. This is a good solution when you need only the sequential execution of the transactions. This way, you do not need to track the nonce off-chain on the client side. Also, the nonce would not go off-sync as it starts from 0 and keeps increasing by 1 with every signed transaction. This also lets the user know what is the last nonce they have used, all the other nonce numbers after that are still not used or valid. For example, if a user has sent 50 transactions and the last nonce used is 49, they know that from 50 onwards, all the nonce values are still valid and have not been used. 84 | 85 | In the upcoming Ethereum hard fork named Istanbul, there would be a new instruction to get the chain ID of the network in the contract. The chain ID is the fixed and unique ID associated with each testnet and mainnet out there. Adding this chain ID to your signature data would ensure that no one can reply to your signatures, which were previously used on testnet and played on mainnet. 86 | -------------------------------------------------------------------------------- /design-patterns/gas-economic/Readme.md: -------------------------------------------------------------------------------- 1 | # Gas economic patterns 2 | 3 | Ether has an economic value and is being traded on exchanges. Ether is used as a crypto fuel to execute transactions on the Ethereum blockchain. In Solidity, each function execution consumes gas. The gas consumed is always paid in ether from the transaction initiator to the block miner. Higher gas consumption by a contract would need more ether; similarly, lower gas consumption would incur a lower amount of ether, and thus lowers the execution cost. Hence, it is always preferred to write the contract in such a way that it can consume the least amount of gas possible for the processing of each transaction. 4 | 5 | One possible way to reduce gas consumption is to always deploy the contract with an enabled optimization flag. This process optimizes the EVM bytecode, which then consumes less gas. 6 | 7 | We will discuss some of the patterns that can be used to reduce the gas consumption of the contract while carrying out certain types of operations. 8 | 9 | ## String equality comparison pattern 10 | 11 | In Solidity, there is no native function to compare the strings. Hence, it is not possible to compare the equality of the two strings. There are ways to do this by checking byte-by-byte data, but it would be a costly operation in terms of gas consumption. Solidity is not ideal for this, so you should think carefully when using this. 12 | 13 | To check for string equality, we can generate the keccak256 hash of both strings and compare the hashes with each other. The generated hash of the two same strings will always give the same hash value. If the strings are not equal, their hashes will also differ. 14 | 15 | The following code should be used to compare two strings for their equality: 16 | 17 | ``` 18 | function compare(string memory a, string memory b) internal returns (bool) { 19 | if(bytes(a).length != bytes(b).length) { 20 | return false; 21 | } else { 22 | return keccak256(a) == keccak256(b); 23 | } 24 | } 25 | ``` 26 | 27 | As you can see, in the compare() function, first, it checks that the length of the strings are equal, then generates the hash, and compares them. If the length of the strings are not equal, it returns false. If the length of both of the strings are equal, then generate the keccak256 hash of both strings and check. The result of the comparison is returned. 28 | 29 | ### Applicability 30 | 31 | The string equality comparison design pattern should be used in the following cases, when: 32 | 33 | - You want to compare two different strings for equality. 34 | - The string length is larger than the two characters. 35 | - There could be multiple sizes of strings passed to a function and we want to have the gas-optimized solution. 36 | 37 | ## Tight variable packing pattern 38 | 39 | Tight variable packing should be utilized when using structs in Solidity. The Solidity language allows structs in the contract, that is used to define an abstract data type. When the storage is allotted to a struct type variable in EVM storage, it is allotted in slots. Each storage slot is 32 bytes long. When statically sized data types are used in the struct (for example, uintX, intX, and bytesX), these variables are allotted storage slots starting from 0 index. Storing and reading data from these storage slots consumes gas based on the number of storage slots written or accessed. Hence, when variables are not tightly packed in a struct, it could consume more storage slots, which would result in more gas consumption during each function call. 40 | 41 | Consider the following example code in which we have a Record struct consisting of four fields: 42 | 43 | ``` 44 | contract StructPacking { 45 | 46 | struct Record { 47 | uint param1; // 1st storage slot 48 | bool valid1; // 2nd storage slot 49 | 50 | uint param2; // 3rd storage slot 51 | bool valid2; // 4th storage slot 52 | } 53 | 54 | Record[] records; 55 | 56 | //Params can be passed to function 57 | function addRecord() public { 58 | Record memory record = Record( 59 | 1, true, 60 | 2, true); 61 | 62 | records.push(record); 63 | } 64 | } 65 | ``` 66 | 67 | When the preceding contract is deployed and the addRecord() function is executed, it consumes 122,414 gas for the transaction cost and 101,142 gas for the execution cost. The EVM allotted four storage slots for the record variable to store. Let's understand how the storage slots are allotted for each of the variables present in the Record struct: 68 | 69 | - param1: This variable is of the uint type (that is, uint256), using 256 bits, meaning 32 bytes. Hence, it would consume a full storage slot. 70 | - valid1: This variable is of the bool, type, which consumes 1 byte. As the first slot is fully consumed in storing param1, EVM would allocate the second storage slot and store the valid1 variable in it. 71 | - param2: This variable is of the uint type, which would also require 32 bytes of storage. As the valid1 variable does not consume a full storage slot, 31 bytes are still free; however, 32 bytes (256 bit) of data cannot be accommodated in 31 bytes storage. Hence, EVM would allocate a new third storage slot for the param2 variable and store it. 72 | - valid2: This variable is of the bool type, which consumes 1 byte. However, the third storage slot is fully occupied by param2, hence valid2 would be stored in a new fourth storage slot. 73 | 74 | In total, four storage slots are allotted to store a Record struct variable. 75 | 76 | You can optimize the struct by reorganizing it and consuming fewer storage slots. Solidity does not perform automatic reorganization to tightly pack struct variables. Hence, this has to be done manually. 77 | 78 | In the following code, we have reorganized the variables present in the Record struct: 79 | 80 | ``` 81 | contract StructPacking { 82 | 83 | struct Record { 84 | uint param1; // 1st storage slot 85 | uint param2; // 2nd storage slot 86 | 87 | bool valid1; // 3rd storage slot 88 | bool valid2; // 3rd storage slot 89 | } 90 | 91 | Record[] records; 92 | 93 | //Params can be passed to function 94 | function addRecord() public { 95 | Record memory record = Record( 96 | 1, 2, true, true); 97 | 98 | records.push(record); 99 | } 100 | } 101 | ``` 102 | 103 | The Solidity optimizer does not optimize structs. 104 | 105 | When the preceding contract is deployed, an addRecord() function is called; it consumes 102,219 gas as the transaction cost and 80,947 gas for the execution cost. If you compare the gas cost difference from a previous execution, this new code with a tightly packed struct consumes less gas by 20,195 gas-per-function call. This is a considerably high gas saving per function call. If this function is called multiple times with the preceding tightly packed struct, you would be able to save a lot of gas units. 106 | 107 | Let's understand how storage slots are allotted by EVM using optimized code: 108 | 109 | - param1: This variable is of the uint type (that is, uint256), using 256, bits meaning 32 bytes. Hence, it would consume a full slot. 110 | - param2: This variable is of the uint type, which would also require 32 bytes of storage. There is no empty space left in the previous storage slot. Hence, EVM would allocate a new second storage slot for the param2 variable and store it. 111 | - valid1: This variable is of the bool type, which consumes 1 byte. As the second storage slot is fully consumed in storing param2, EVM would allocate the third slot and store the valid1 variable in it. 112 | - valid2: This variable is of the bool type, which consumes 1 byte. However, the third storage slot is not fully occupied, hence, the valid2 variable will be stored in the third storage slot. 113 | 114 | This way, the new optimized code would consume only three storage slots in storing a variable of the Record type struct. 115 | 116 | Let's understand when the tight variable packing pattern should be used for a struct. 117 | A bool variable in Solidity takes 1 byte to store its value. 118 | 119 | ### Applicability 120 | 121 | A tight variable packing pattern is only applicable to struct types. It is the developer's responsibility to check the structs used in each contract and ensure that they are tightly packed. Tight packing should be used only when you are certain that a lot of gas could be saved by optimizing the struct. Otherwise, if it is not making any significant difference, you can avoid it. 122 | -------------------------------------------------------------------------------- /known-attack-patterns/front-running-attacks.md: -------------------------------------------------------------------------------- 1 | # Front-running attacks 2 | 3 | The Ethereum blockchain is slow, and it is a public blockchain. Because it is a public blockchain, all the transaction data is open and can be seen by others. Even when a transaction is in the pending state, its data can be seen by others. 4 | 5 | A transaction can be processed slowly or quickly, depending on the quantity of the gas fees each transaction is going to give to the miner to execute and add to the blockchain. A transaction paying higher gas fees are picked up by the miners first and added to the blockchain. On the other hand, if a transaction is paying lower gas fees, they are picked up later when miners are free and not many higher gas fees transactions are in the pending state. In other words, your transaction is chosen to be executed based on the higher gas fees a miner can earn for executing it. When a transaction is not processed due to low gas fees, it will remain in the pool and be in the pending transaction state. 6 | 7 | Once a transaction is in the pending state, all the blockchain clients sync up their pending transactions as well; hence, a pending transaction is also known to each and every client node. You can write a program or script that would listen for any transactions initiated from a specific wallet or with specific parameters. One can also find all pending transactions and see its transaction data. 8 | 9 | In a front-running attack, an attacker sees transaction A (which is in pending state), and they immediately send transaction B with a higher gas price to get economic benefit. 10 | 11 | Let's discuss the front-running attack that is possible with a specific implementation of ERC20's approve() function. 12 | 13 | ## Example of an ERC20 approve function 14 | 15 | In the ERC20 token standard, there is a function called approve(), following is the implementation code for it. You can also refer Chapter 7, ERC20 Token Standard, The approve function, for more details on the working of the code: 16 | 17 | ``` 18 | function approve(address spender, uint tokens) 19 | public returns (bool success) 20 | { 21 | allowed[msg.sender][spender] = tokens; 22 | Approval(msg.sender, spender, tokens); 23 | return true; 24 | } 25 | ``` 26 | 27 | This function is always prone to a front-running attack if not handled correctly. Let's see how a front-running attack happens on the approve() function, with the help of the following diagram, showing a transaction flow step by step: 28 | front running 29 | 30 | Front-running attack transaction flow 31 | 32 | In the preceding diagram we have the following: 33 | 34 | - There are two people named Alice (left) and Bob (right) 35 | - There is an ERC20 token contract (symbol: TKN) on which both Alice and Bob interact and initiate transactions 36 | - Initially, Alice holds 3,000 TKN and Bob holds 0 TKN 37 | - We are assuming that both have sufficient ether present in their wallets, in order to initiate transactions 38 | - The sequence of actions are numbered from 1 to 6 in the preceding diagram 39 | 40 | Let's go through each numbered action and transactions happened between both Alice and Bob: 41 | 42 | 1. Alice initiates a transaction (Tx-1) and calls the approve(Bob, 1000) function on the TKN contract to give approval of 1,000 TKN tokens to Bob. This transaction is executed, confirmed, and Bob is approved for 1,000 TKN. 43 | 2. Bob starts listening for events on the blockchain. He keeps listening for an event when any transaction from Alice is initiated. He also gets Alice in confidence that she approved fewer tokens; originally, he wanted to have 1,500 TKN approved. It could also be that Alice and Bob communicated and agreed—before Tx-1 happened—that Bob actually needs 1,500 TKN; however, by mistake, Alice approved only 1,000 TKN. 44 | 3. Now, Alice realized the mistake, initiated a transaction (Tx-2), and calls the approve(Bob, 1500) function to approve 1,500 TKN tokens to Bob. 45 | 4. Bob immediately got the notification from his event listener that Alice initiated the new Tx-2 transaction (the transaction is still in the pending state) to give him approval for 1,500 TKN. However, before Tx-2 gets confirmed, Bob initiated transaction Tx-3 (to front-run Tx-2), and calls the transferFrom(Alice, Bob, 1000) function to transfer 1,000 TKN from Alice's account to Bob's account as he already has 1,000 TKN approved. Bob initiate this transaction with the higher gas price to get his Tx-3 transaction confirmed and executed before transaction Tx-2. For example, transaction Tx-2 is initiated with a gas price of 21 gwei. Bob will initiate his Tx-3 transaction with a gas price of more than 21 gwei, for example, 40 gwei. We assume that Bob's transaction Tx-3 gets confirmed and executed before Alice's transaction, Tx-2. Hence, transaction Tx-3 would transfer 1,000 TKN from Alice's account to Bob's. After this transaction, Alice has 2,000 TKN and Bob has 1,000 TKN in their respective wallets. Also, Bob's approved balance would be 0 TKN after transaction Tx-3, as he has used the approval and transferred 1,000 TKN tokens. 46 | 5. Now, Alice's Tx-2 transaction got confirmed and executed. This transaction gave Bob a fresh approval of 1,500 TKN. 47 | 6. As Bob is already listening for events, he gets a notification that transaction Tx-2 is also confirmed and executed. He immediately initiates another transaction, Tx-4, and calls the transferFrom(Alice, Bob, 1500) function. Once this Tx-4 transaction is confirmed, Alice would have 500 TKN left in her wallet, and Bob would have managed to get 2,500 TKN by performing a front-running attack. 48 | 49 | As we have seen in the preceding example; originally Alice wanted to approve 1,500 TKN tokens only, however Bob end up getting 2,500 TKN tokens. 50 | 51 | We discussed how a front-running attack can be used by an attacker to transfer more tokens than intended. Let's discuss the front-running prevention techniques. 52 | 53 | ## Preventing an attack on the approve function 54 | 55 | To overcome an attack on the approve function, there are different techniques. 56 | 57 | For the previously discussed problem of the approve function, one solution is to set the allowance to 0 (zero) before setting it again with a new value: 58 | 59 | ``` 60 | function approve(address spender, uint tokens) 61 | public returns (bool success) 62 | { 63 | require((tokens == 0) || (allowed[msg.sender][spender] == 0)); 64 | allowed[msg.sender][spender] = tokens; 65 | Approval(msg.sender, spender, tokens); 66 | return true; 67 | } 68 | ``` 69 | 70 | The preceding code would prevent the front-running attack and would enforce that the approver would always set the allowance to 0 (zero) before setting it again with a new non-zero value. However, this technique requires two transactions in case the approver wants to change the allowance. 71 | 72 | Here is another technique in which two extra functions are provided by the contract. These functions would allow the approver to increase or decrease the allowance when required. The code for these functions is as follows: 73 | 74 | ``` 75 | function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { 76 | require(spender != address(0)); 77 | 78 | _allowed[msg.sender][spender] = 79 | _allowed[msg.sender][spender].add(addedValue); 80 | emit Approval(msg.sender, spender, _allowed[msg.sender][spender]); 81 | return true; 82 | } 83 | 84 | function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { 85 | require(spender != address(0)); 86 | 87 | _allowed[msg.sender][spender] = 88 | _allowed[msg.sender][spender].sub(subtractedValue); 89 | emit Approval(msg.sender, spender, _allowed[msg.sender][spender]); 90 | return true; 91 | } 92 | ``` 93 | 94 | The increaseAllowance() function would allow the approver to increase the allowance by the provided number of tokens. However, the decreaseAllowance() function would allow the approver to decrease the allowance. Using these functions, the front-running attack is prevented. You can also refer Chapter 7, ERC20 Token Standard, Advance functions, for more details on these functions. 95 | 96 | ## Other front-running attacks 97 | 98 | We only discussed the approve() function-specific front-running attack. However, other kinds of front-running attacks can also happen. For example, when a user is registering a unique value, once this is registered, no one is allowed to register it again on the same contract. Like the domain name registration, once it is registered with a user, another person cannot register it again, as the first person has became the owner of that. 99 | 100 | An attacker can watch for the transactions on that contract and can send the high gas-price transaction to front run the user's transaction. 101 | 102 | To prevent this type of front-running attack, you should use the commit-and-reveal scheme. We discussed this technique in this chapter when we were discussing about not sharing confidential information on chain in the Avoid sharing a secret on-chain section. 103 | 104 | This type of attack is mostly dependent upon how you write your contract code. If your contract is vulnerable to front-running attacks and have some ether fund movements linked to it, an attacker could attack your contracts more often to gain more ether. 105 | 106 | Anyone is allowed to initiate a transaction with a high gas price specified in the transaction. For this, they can watch the current network's high gas price and send a transaction with a higher gas price than that. For example, the current networks' high gas price is X wei. They can send a transaction with X + Y wei to get their transaction added to the block as soon as possible. 107 | -------------------------------------------------------------------------------- /design-patterns/security/Readme.md: -------------------------------------------------------------------------------- 1 | # Security patterns 2 | 3 | There are a few security patterns that ensure the security of funds in a contract. Using these patterns, you can improve the security of the contract. Using these patterns, you could eradicate common security issues in the contract. In the year 2018, there were more than $1 billion smart contract-related hacks. The patterns that we are discussing are built to avoid developers mistakes while developing smart contracts. 4 | 5 | Let's look at some of the security design patterns. 6 | 7 | ## Withdrawal pattern 8 | 9 | The withdrawal pattern is also known as a pull-over-push pattern. In this pattern, ether or token transfer (push) from the contract is avoided; rather, the user is allowed to pull ether or token from the contract. 10 | 11 | There can be many contracts in which you want to send ether or token to multiple addresses or to a group of addresses. Sending ether from a contract via iterative or non-iterative methods is always going to cause problems, so this should be avoided. Consider the following DividendContract sample code of the contract. Using this contract, you can distribute the dividend to your investors: 12 | 13 | ``` 14 | contract DividendContract is Ownable { 15 | 16 | address[] public investors; 17 | 18 | function registerInvestor(address _investor) public onlyOwner { 19 | require(_investor != address(0)); 20 | investors.push(_investor); 21 | } 22 | 23 | //Bad Practice 24 | function distributeDividend() public onlyOwner { 25 | for(uint i = 0; i < investors.length; i++) { 26 | uint amount = calculateDividend(investors[i]); 27 | investors[i].transfer(amount); //Push ether to user 28 | } 29 | } 30 | 31 | function calculateDividend(address _investor) internal returns(uint) { 32 | //Dividend calculation here 33 | } 34 | } 35 | ``` 36 | 37 | The contract maintains the list of investors in the investors array. Only the owner of the contract can add investors who are eligible to receive the dividend. The ether present in the contract will be distributed as dividends. As you can see in the distributeDividend() function, there is an unbounded loop and it will iterate the number of times equals the investors array length. There could be multiple issues in the preceding code, such as the following: 38 | 39 | - In the future, there could be an out-of-gas exception due to this loop as the amount of gas consumption would increase linearly according to the increase in the investor list, hence it's dangerous to do this iteratively. There is no way to remove an investor from an array; hence, once the loop starts consuming more gas units than a block gas limit, the transaction to this function call will always fail. It is dangerous to write loops like this way. This will lead to the locking of ether in the contract, assuming that there is no other way to take funds out of the contract. 40 | - It is possible that the address of an investor is a contract address, which has a continually failing fallback function. This leads to whole transaction failure for the distributeDividend() function call each time. This also leads to the locking of ether in the contract. 41 | 42 | To avoid the issues described in the preceding text, the contract should be designed in a way that a user should be able to claim their dividend from the contract. This way, it's the onus of the user to pull the funds. As you can see in the following code, we have the claimDividend() function, that can be called by anyone. However, only the user who has valid balances present in the contract can claim dividends, as shown in the following: 43 | 44 | ``` 45 | //Good Practice - Pull ether 46 | function claimDividend() public { 47 | uint amount = balances[msg.sender]; 48 | require(amount > 0); 49 | //Ensure to update balance before transfer 50 | //to avoid reentrancy attack 51 | balances[msg.sender] = 0; 52 | msg.sender.transfer(amount); 53 | } 54 | ``` 55 | 56 | The contract should maintain or update the balances of each user or investor accordingly, so that they can withdraw the balance amount from the contract, as, in the preceding code, the balances mapping must be updated via other functions. 57 | 58 | Let's take a look at when the withdrawal pattern should be applied. 59 | 60 | ### Applicability 61 | 62 | We should use the withdrawal pattern or pull-over-push pattern in the following cases, when: 63 | 64 | - You want to send ether/token to multiple addresses from the contract. 65 | - You want to avoid the risk associated with transferring ether/token from the contract to the users. 66 | - You want to avoid paying transaction fees as we know, the transaction initiator has to pay the transaction fee to get their transaction included in the blockchain. Hence, you may want to avoid paying transaction fees for transferring ether or token (push transaction) from the contract to your users. Instead, you want your users to pay transaction fees (pull transaction) and get their share of ether/token withdrawn from the contract. 67 | 68 | ## Access restriction pattern 69 | 70 | As the name suggests, the access restriction design pattern restricts access to the functions of the contract based on roles. The Ethereum blockchain is public and all the addresses and transaction data is public to everyone. However, we can define the contract state variables as private; doing this it only restricts reading the state variable from the contract. Still, anyone can follow the transactions and can find the values of the private state variables present in the contract. To allow anyone to call a function present in the contract, it should be defined as public or external. However, when you need restricted access to a function, you should use modifiers to check for the access rights. 71 | 72 | In the following example code, we have two address state variables—owner and admin. The access restriction requirements are as follows: 73 | 74 | - The owner variable stores the address of the contract owner. Only the owner of the contract is allowed to change the admin address using the changeAdmin() function. 75 | - The admin variables store the address of the contract admin. 76 | - Both owner and admin are authorized to pause the contract via the pause() function: 77 | 78 | Let's have a look at the AccessControl contract: 79 | 80 | ``` 81 | contract AccessControl { 82 | address public owner; 83 | address public admin; 84 | 85 | bool public paused; 86 | modifier whenPaused() { 87 | require(paused); 88 | _; 89 | } 90 | 91 | modifier whenNotPaused() { 92 | require(!paused); 93 | _; 94 | } 95 | 96 | modifier onlyOwner() { 97 | require(msg.sender == owner); 98 | _; 99 | } 100 | 101 | modifier onlyAdmin() { 102 | require(msg.sender == admin); 103 | _; 104 | } 105 | 106 | modifier onlyAuthorized() { 107 | require(msg.sender == owner || msg.sender == admin); 108 | _; 109 | } 110 | 111 | function changeAdmin(address _newAdmin) public onlyOwner { 112 | require(_newAdmin != address(0)); 113 | admin = _newAdmin; 114 | } 115 | 116 | function pause() public onlyAuthorized whenNotPaused { 117 | paused = true; 118 | } 119 | } 120 | ``` 121 | 122 | As you can see in the preceding code, the following is true: 123 | 124 | - The changeAdmin() function is only allowed to be executed from the owner address as it is restricted with an onlyOwner modifier. This function is always allowed to be called from owner, as it is not protected with either the whenPaused or whenNotPaused modifiers. 125 | - The pause() function is allowed to be executed by an authorized person as it is restricted with an onlyAuthorized modifier. Both the admin and owner addresses are authorized to call this function. Also, the precondition to call this function is that the state must not have been previously paused, as it is protected with the whenNotPaused modifier. 126 | 127 | Let's see when the access restriction pattern should be used. 128 | 129 | ### Applicability 130 | 131 | The access restriction pattern should be used in the following cases, when: 132 | 133 | - Some functions should only be allowed to be executed from certain roles 134 | - Similar kinds of roles and access are needed for one or more functions or actions 135 | - You want to improve the security of the contracts from unauthorized function calls 136 | 137 | > Note : This pattern is available in the openzeppelin contracts library in AccessControl.sol contract. 138 | 139 | ## Emergency stop pattern 140 | 141 | The emergency stop design pattern allows the contract to pause and stop the function calls that could harm the contract state or funds present in the contract. As we know that Ethereum smart contracts are immutable once deployed on the blockchain, it might be possible that the contract can have bugs after deployment and could be found by an attacker to gain the control over the contract or funds. To handle these emergency situations, this design pattern could be helpful to reduce the damage to the contract. 142 | 143 | It is important to note that when an emergency stop is activated on a contract, all its stakeholders must be able to see the current state of the contract. This should be done to ensure that the stakeholders get the correct status of the contract as they trust the owner of the contracts (maybe a company in this case). 144 | 145 | The emergency stop or pause should only be in control of the owner or authorized person. Only they are allowed to call these functions. However, pausing or stopping the contract could potentially add trust issues to the contracts. You should avoid using this pattern; however, in cases when centralized control is needed, these functions can be added to improve the security of the funds and contracts. For example, the project called Wrapped BTC (WBTC) has WBTC tokens on Ethereum blockchain. Each WBTC token is pegged to one bitcoin (BTC). This project has used pausing functionality to pause the token transfer. The owner of the contract is allowed to pause the contract in extreme circumstances. You can see its code present on GitHub at https://github.com/WrappedBTC/bitcoin-token-smart-contracts/blob/master/contracts/token/WBTC.sol. 146 | 147 | In the following code sample, we have a contract called Deposit. This contract holds the funds deposited to this contract: 148 | 149 | ``` 150 | contract Deposit { 151 | 152 | address public owner; 153 | bool paused = false; 154 | 155 | modifier onlyOwner() { 156 | require(msg.sender == owner); 157 | _; 158 | } 159 | 160 | modifier whenPaused() { 161 | require(paused); 162 | _; 163 | } 164 | 165 | modifier whenNotPaused() { 166 | require(! paused); 167 | _; 168 | } 169 | 170 | constructor() public { 171 | owner = msg.sender; 172 | } 173 | 174 | function pause() public onlyOwner whenNotPaused { 175 | paused = true; 176 | } 177 | 178 | function unpause() public onlyOwner whenPaused { 179 | paused = false; 180 | } 181 | 182 | function deposit() public payable whenNotPaused { 183 | //Ether deposit logic here 184 | } 185 | 186 | function emergencyWithdraw() public onlyOwner whenPaused { 187 | owner.transfer(address(this).balance); 188 | } 189 | } 190 | ``` 191 | 192 | As you can see, the owner of the contract is allowed to pause or unpause the contract: 193 | 194 | - The owner can call the pause() function to pause the contract, which, in turn, stops the deposit of the funds and allows onlyOwner to call the emergencyWithdraw() function. 195 | - The owner can call the unpause() function to unpause the contract. This puts the contract back to normal and should allow the deposit of funds again. 196 | 197 | Let's see when and where the emergency stop pattern should be used. 198 | 199 | ### Applicability 200 | 201 | The emergency stop design pattern should be used in the following cases, when: 202 | 203 | - You want your contract to be handled differently in case of any emergency situations 204 | - You want the ability to pause the contract functions in unwanted situations 205 | - In case of any failure, you want to stop contract failure or state corruption 206 | 207 | > Note : This pattern is available in the openzeppelin contracts library in Pausable.sol contract. 208 | -------------------------------------------------------------------------------- /design-patterns/behavioral/Readme.md: -------------------------------------------------------------------------------- 1 | # Behavioral patterns 2 | 3 | The behavioral design patterns are used when a contract behaves differently according to its current state. In Solidity, we can have a contract in different states based on the values of its variables. These behaviors should be defined in the contract definition. According to the behavior defined in a contract, a contract transitions between different states. Let's look at some of the behavioral design patterns. 4 | 5 | ## State machine pattern 6 | 7 | In a state machine, the initial state and the final state are known for the machine/process. Between these two states, there could be more intermediate states. In each state, different behaviors or functions are allowed on the machine. For example, a vending machine is a state machine, in which it first asks for the user to select the item number, and, once selected, it moves to the collect amount state. Once the amount is paid by the user, it dispenses the item requested by the user and, at last, the process ends. 8 | 9 | The state machine pattern allows a contract to transition from different states and enables certain functions to be executed in each state. 10 | 11 | A Solidity contract can be designed in such a way that it represents the state in which it transitioned. Based on the state of the contract, you can allow or disallow functions present in the contract. Using the state machine pattern, you can define different states according to your needs and transition the contract from its initial state to its final state. During this transition, the processing of the contract can allow or disallow its functions, so it can successfully transition to its next state. 12 | 13 | In the following code, we have a LoanContract example. As you can see, it has an enum LoanState, which represents different states in which a contract can transition. Let's understand the meaning of the different states: 14 | 15 | - NONE: No state represented 16 | - INITIATED: When a loan is initiated by borrower 17 | - COLLATERAL_RCVD: When collateral is received from borrower in the contract 18 | - FUNDED: When the loan received the required collateral from borrower and lender funded the loan 19 | - REPAYMENT: When borrower accepted the funding and starts repaying the loan 20 | - FINISHED: When the loan has finished, and borrower has paid off the full loan 21 | 22 | The following is the code for the LoanContract contract: 23 | 24 | ``` 25 | contract LoanContract { 26 | enum LoanState { NONE, INITIATED, COLLATERAL_RCVD, FUNDED, 27 | REPAYMENT, FINISHED } 28 | 29 | address public borrower; 30 | address public lender; 31 | IERC20 token; 32 | uint collateralAmount; 33 | uint loanAmount; 34 | LoanState public currentState; 35 | 36 | modifier onlyBorrower() { 37 | require(msg.sender == borrower); 38 | _; 39 | } 40 | 41 | modifier atState(LoanState loanState) { 42 | require(currentState == loanState); 43 | _; 44 | } 45 | 46 | modifier transitionToState(LoanState nextState) { 47 | _; 48 | currentState = nextState; 49 | } 50 | 51 | constructor(IERC20 _token, uint _collateralAmount, uint _loanAmount) 52 | public transitionToState(LoanState.INITIATED) { 53 | borrower = msg.sender; 54 | token = _token; 55 | collateralAmount = _collateralAmount; 56 | loanAmount = _loanAmount; 57 | } 58 | 59 | function putCollateral() 60 | public 61 | onlyBorrower 62 | atState(LoanState.INITIATED) 63 | transitionToState(LoanState.COLLATERAL_RCVD) 64 | { 65 | require(IERC20(token) 66 | .transferFrom(borrower, address(this), collateralAmount)); 67 | } 68 | //Rest of the code 69 | } 70 | ``` 71 | 72 | In the preceding code, we have an atState() modifier, which is used to check the current state of the loan. The transitionToState modifier is used to transition the contract state from one state to another. As you can see in the putCollateral() function, we used the atState(LoanState.INITIATED) modifier. This allows the function call only in the INITIATED state. Once the function call is executed successfully, it transitions from the INITIATED state to the COLLATERAL_RCVD (collateral received) state. 73 | 74 | Let's understand when and where the state machine pattern can be applied. 75 | 76 | ### Applicability 77 | 78 | The state machine pattern should be used in the following cases, when: 79 | 80 | - A contract needs to transition from different states 81 | - A contract needs to allow different functions and to behave differently during each of the intermediate states 82 | 83 | ## Iterable map pattern 84 | 85 | The iterable map pattern allows you to iterate over the mapping entries. 86 | 87 | In Solidity, you can define a mapping. The mapping holds the key-value pairs. However, there is no way to iterate over the mapping entries in Solidity. There are some cases for which you would need to iterate over the mapping entries; for these situations, you can use this pattern. 88 | 89 | Note that the iteration over the mapping entries should not cause an out-of-gas exception. To avoid these situations, use the iteration only in the view function. This way, you would execute a function via message calls only, without generating a transaction. 90 | 91 | In the following code, we have DepositContract, in which anyone can deposit ether. When ether is deposited, its entry is updated in the balances mapping to track how much ether is deposited. It also adds an entry into the holders address array, which is used to maintain the unique list of addresses that have been deposited in the contract: 92 | 93 | ``` 94 | contract DepositContract is Ownable { 95 | 96 | mapping(address => uint) public balances; 97 | address[] public holders; 98 | 99 | function deposit() public payable { 100 | require(msg.value > 0); 101 | bool exists = balances[msg.sender] != 0; 102 | if (!exists) { 103 | holders.push(msg.sender); 104 | } 105 | balances[msg.sender] += msg.value; 106 | } 107 | 108 | function getHoldersCount() public view returns (uint) { 109 | return holders.length; 110 | } 111 | } 112 | ``` 113 | 114 | As you can see in the preceding code; in the deposit() function a new depositor address is added in holders array. Using this holders array you can iterate over the balances mapping 115 | 116 | Using the holders address array, you can find the count of depositors in the contract by calling the getHoldersCount() function. Similarly, if you need to filter out some data mapping, you can do it by writing a view function. 117 | 118 | ### Applicability 119 | 120 | The iterable map pattern should be used in the following cases, when: 121 | 122 | - You need iterable behaviors over the Solidity mappings 123 | - There would be fewer mapping entries that would require iterable behavior 124 | - You would need to filter some data out of the mapping and get the result via a view function 125 | 126 | ## Indexed map pattern 127 | 128 | The indexed map pattern allows you to read an entry from a map using an index. The pattern also allows you to remove an item from a map and an array. 129 | 130 | As we have seen in the previous section, in an iterable map pattern, an item is added to a map as well as to an array. Using the iterable map, we can fetch records using an index. However, the iterable map pattern is useful when you just want to keep on adding items in a map and in an array; it does not support the removal of an item. Hence, when you want to remove an item from the map and array, things get a little tricky. Here, in the IndexedMapping library contract, we can maintain the list of items and remove them from the list as well: 131 | 132 | ``` 133 | library IndexedMapping { 134 | struct Data { 135 | mapping(address=>bool) valueExists; 136 | mapping(address=>uint) valueIndex; 137 | address[] valueList; 138 | } 139 | 140 | function add(Data storage self, address val) internal returns (bool) { 141 | if (exists(self, val)) return false; 142 | 143 | self.valueExists[val] = true; 144 | self.valueIndex[val] = self.valueList.push(val) - 1; 145 | return true; 146 | } 147 | 148 | function remove(Data storage self, address val) internal returns 149 | (bool) { 150 | uint index; 151 | address lastVal; 152 | 153 | if (!exists(self, val)) return false; 154 | 155 | index = self.valueIndex[val]; 156 | lastVal = self.valueList[self.valueList.length - 1]; 157 | 158 | // replace value with last value 159 | self.valueList[index] = lastVal; 160 | self.valueIndex[lastVal] = index; 161 | self.valueList.length--; 162 | 163 | // remove value 164 | delete self.valueExists[val]; 165 | delete self.valueIndex[val]; 166 | 167 | return true; 168 | } 169 | 170 | function exists(Data storage self, address val) internal view 171 | returns (bool) { 172 | return self.valueExists[val]; 173 | } 174 | 175 | function getValue(Data storage self, uint index) internal view 176 | returns (address) { 177 | return self.valueList[index]; 178 | } 179 | 180 | function getValueList(Data storage self) internal view returns 181 | (address[]) { 182 | return self.valueList; 183 | } 184 | } 185 | ``` 186 | 187 | We have defined the IndexedMapping contract as a library so that it can be used in any contract. As you can see, we have a Data struct to maintain the data for this library. In the Data struct, we have the following variables: 188 | 189 | - valueExists: This is a map from the address type to the bool type. This map entry tells us whether a particular address exists in the list or not. When an address exists, its bool value will be set to true, otherwise, it will be set to false. 190 | - valueIndex: This is a map from the address type to the uint type. This map entry stores the address to array index mapping. 191 | - valueList: This is an array of addresses. This stores the addresses in the list. 192 | 193 | As you can see, there are two functions (add() and remove()) to add and remove an item from the address list. The getValue() function is used to ensure an item is present at the specified index in an array. 194 | 195 | Let's see where the indexed map pattern can be applied. 196 | 197 | ### Applicability 198 | 199 | The indexed map pattern can be used in the following cases, when: 200 | 201 | - You want indexed access of an element in a single operation (order of 1 O(1) operation), instead of iterating an array of elements. This is only when the iterable map feature is also required. 202 | - You also want indexed access for elements along with support to remove elements from the list. 203 | 204 | ## Address list pattern 205 | 206 | The address list pattern is used to maintain a curated list of addresses by the owner. 207 | 208 | In contracts, there are some situations in which you would need a curated list of addresses. For example, you would need a list of whitelisted addresses that are allowed to call a certain function of your contract. Another example is when you want to maintain a list of supported tokens addresses to allow your contracts to interact with these selected tokens only. 209 | 210 | In the address list pattern, adding and removing addresses from the list can only be done by the owner of the contract. In the following code, we have an AddressList contract: 211 | 212 | ``` 213 | contract AddressList is Ownable { 214 | 215 | mapping(address => bool) internal map; 216 | 217 | function add(address _address) public onlyOwner { 218 | map[_address] = true; 219 | } 220 | 221 | function remove(address _address) public onlyOwner { 222 | map[_address] = false; 223 | } 224 | 225 | function isExists(address _address) public view returns (bool) { 226 | return map[_address]; 227 | } 228 | } 229 | ``` 230 | 231 | As you can see in the code, only the owner can add or remove addresses in the contract by calling the add() or remove() functions. The isExists() function is a view function and is open for anyone to call. Another contract can even call this function to check whether an address is present in this list or not. 232 | 233 | Let's understand where the address list pattern should be applied. 234 | 235 | ### Applicability 236 | 237 | The address list pattern should be used in the following cases, when: 238 | 239 | - You want to maintain a curated list of addresses. 240 | - You want to maintain the whitelisted address, which is allowed/disallowed to perform a certain task. 241 | - You want to maintain a list of contract addresses that are allowed. For example, an address list of ERC20 token contract addresses. 242 | 243 | ## Subscription pattern 244 | 245 | The subscription pattern is used when you need to provide a periodic subscription fee for any kind of service. 246 | 247 | A contract can provide different kinds of features or a premium service. Any subscriber can subscribe for services that your contract provides. To enable this, you can charge a subscription fee for a period of time from the subscriber. To implement this service, you can create a Subscription contract, as we have developed in the following code example: 248 | 249 | ``` 250 | contract Subscription is Ownable { 251 | using SafeMath for uint; 252 | //subscriber address => expiry 253 | mapping(address => uint) public subscribed; 254 | address[] public subscriptions; 255 | uint subscriptionFeePerDay = 1 ether; 256 | 257 | modifier whenExpired() { 258 | require(isSubscriptionExpired(msg.sender)); 259 | _; 260 | } 261 | 262 | modifier whenNotExpired() { 263 | require( ! isSubscriptionExpired(msg.sender)); 264 | _; 265 | } 266 | 267 | constructor(uint _subscriptionFeePerDay) public { 268 | subscriptionFeePerDay = _subscriptionFeePerDay; 269 | } 270 | 271 | function isSubscriptionExpired(address _addr) public view returns 272 | (bool) { 273 | uint expireTime = subscribed[_addr]; 274 | return expireTime == 0 || now > expireTime; 275 | } 276 | 277 | function subscribe(uint _days) public payable whenExpired { 278 | require(_days > 0); 279 | require(msg.value == subscriptionFeePerDay.mul(_days)); 280 | subscribed[msg.sender] = now.add((_days.mul(1 days))); 281 | subscriptions.push(msg.sender); 282 | } 283 | 284 | function withdraw() public onlyOwner { 285 | owner().transfer(address(this).balance); 286 | } 287 | 288 | function useService() public whenNotExpired { 289 | //User allowed to use service 290 | } 291 | } 292 | ``` 293 | 294 | As you can see, in this Subscription contract, at the time of deployment, we have configured subscription-per-day fees. This fee is charged per day to the subscriber. The subscriber will call the subscribe() function to subscribe for the service for a given number of days. To do this, they have to send the ether along with the function call. After a successful subscription, they will be able to call the useService() function to use the service until it expires. Once the service of a subscriber expires, they can renew their subscription by calling the subscribe() function again. The owner of the contract can withdraw subscription payments from the contract at any time. 295 | 296 | Let's discuss when this subscription pattern can be used. 297 | 298 | ### Applicability 299 | 300 | The subscription pattern can be used in the following cases, when: 301 | 302 | - You have a periodic paid service-based model 303 | - A user has an existing request and they want to purchase a premium status for their request for a limited period of time 304 | - An existing contract can purchase a premium status for a limited duration 305 | --------------------------------------------------------------------------------