├── LICENSE ├── README.md ├── _config.yml └── solidity-security.md /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Manoj P R 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Solidity Cheatsheet and Best practices 2 | 3 | ## Motivation 4 | 5 | This document is a cheatsheet for **Solidity** that you can use to write **Smart Contracts** for **Ethereum** based blockchain. 6 | 7 | This guide is not intended to teach you Solidity from the ground up, but to help developers with basic knowledge who may struggle to get familiar with Smart Contracts and Blockchain because of the Solidity concepts used. 8 | 9 | > **Note:** If you have basic knowledge in JavaScript, it's easier to learn Solidity. 10 | 11 | 12 | ## Table of contents 13 | 14 | - [Solidity Cheatsheet and Best practices](#solidity-cheatsheet-and-best-practices) 15 | * [Motivation](#motivation) 16 | * [Table of contents](#table-of-contents) 17 | * [Version pragma](#version-pragma) 18 | * [Import files](#import-files) 19 | * [Types](#types) 20 | + [Boolean](#boolean) 21 | + [Integer](#integer) 22 | + [Address](#address) 23 | - [balance](#balance) 24 | - [transfer and send](#transfer-and-send) 25 | - [call](#call) 26 | - [delegatecall](#delegatecall) 27 | - [callcode](#callcode) 28 | + [Array](#array) 29 | + [Fixed byte arrays](#fixed-byte-arrays) 30 | + [Dynamic byte arrays](#dynamic-byte-arrays) 31 | + [Enum](#enum) 32 | + [Struct](#struct) 33 | + [Mapping](#mapping) 34 | * [Control Structures](#control-structures) 35 | * [Functions](#functions) 36 | + [Structure](#structure) 37 | + [Access modifiers](#access-modifiers) 38 | + [Parameters](#parameters) 39 | - [Input parameters](#input-parameters) 40 | - [Output parameters](#output-parameters) 41 | + [Constructor](#constructor) 42 | + [Function Calls](#function-calls) 43 | - [Internal Function Calls](#internal-function-calls) 44 | - [External Function Calls](#external-function-calls) 45 | - [Named Calls](#named-calls) 46 | - [Unnamed function parameters](#unnamed-function-parameters) 47 | + [Function type](#function-type) 48 | + [Function Modifier](#function-modifier) 49 | + [View or Constant Functions](#view-or-constant-functions) 50 | + [Pure Functions](#pure-functions) 51 | + [Payable Functions](#payable-functions) 52 | + [Fallback Function](#fallback-function) 53 | * [Contracts](#contracts) 54 | + [Creating contracts using `new`](#creating-contracts-using--new-) 55 | + [Contract Inheritance](#contract-inheritance) 56 | - [Multiple inheritance](#multiple-inheritance) 57 | - [Constructor of base class](#constructor-of-base-class) 58 | + [Abstract Contracts](#abstract-contracts) 59 | * [Interface](#interface) 60 | * [Events](#events) 61 | * [Library](#library) 62 | * [Using - For](#using---for) 63 | * [Error Handling](#error-handling) 64 | * [Global variables](#global-variables) 65 | + [Block variables](#block-variables) 66 | + [Transaction variables](#transaction-variables) 67 | + [Mathematical and Cryptographic Functions](#mathematical-and-cryptographic-functions) 68 | + [Contract Related](#contract-related) 69 | 70 | 71 | ## Version pragma 72 | 73 | `pragma solidity ^0.5.2;` will compile with a compiler version >= 0.5.2 and < 0.6.0. 74 | 75 | 76 | ## Import files 77 | 78 | `import "filename";` 79 | 80 | `import * as symbolName from "filename";` or `import "filename" as symbolName;` 81 | 82 | `import {symbol1 as alias, symbol2} from "filename";` 83 | 84 | 85 | ## Types 86 | 87 | ### Boolean 88 | 89 | `bool` : `true` or `false` 90 | 91 | Operators: 92 | 93 | - Logical : `!` (logical negation), `&&` (AND), `||` (OR) 94 | - Comparisons : `==` (equality), `!=` (inequality) 95 | 96 | ### Integer 97 | 98 | Unsigned : `uint8 | uint16 | uint32 | uint64 | uint128 | uint256(uint)` 99 | 100 | Signed : `int8 | int16 | int32 | int64 | int128 | int256(int) ` 101 | 102 | Operators: 103 | 104 | - Comparisons: `<=`, `<`, `==`, `!=`, `>=` and `>` 105 | - Bit operators: `&`, `|`, `^` (bitwise exclusive or) and `~` (bitwise negation) 106 | - Arithmetic operators: `+`, `-`, unary `-`, unary `+`, `*`, `/`, `%`, `**` (exponentiation), `<<` (left shift) and `>>` (right shift) 107 | 108 | ### Address 109 | 110 | `address`: Holds an Ethereum address (20 byte value). 111 | `address payable` : Same as address, but includes additional methods `transfer` and `send` 112 | 113 | Operators: 114 | 115 | - Comparisons: `<=`, `<`, `==`, `!=`, `>=` and `>` 116 | 117 | Methods: 118 | 119 | #### balance 120 | 121 | - `
.balance (uint256)`: balance of the Address in Wei 122 | 123 | #### transfer and send 124 | 125 | - `
.transfer(uint256 amount)`: send given amount of Wei to Address, throws on failure 126 | - `
.send(uint256 amount) returns (bool)`: send given amount of Wei to Address, returns false on failure 127 | 128 | #### call 129 | - `
.call(...) returns (bool)`: issue low-level CALL, returns false on failure 130 | 131 | #### delegatecall 132 | 133 | - `
.delegatecall(...) returns (bool)`: issue low-level DELEGATECALL, returns false on failure 134 | 135 | Delegatecall uses the code of the target address, taking all other aspects (storage, balance, ...) from the calling contract. The purpose of delegatecall is to use library code which is stored in another contract. The user has to ensure that the layout of storage in both contracts is suitable for delegatecall to be used. 136 | 137 | ```solidity 138 | contract A { 139 | uint value; 140 | address public sender; 141 | address a = address(0); // address of contract B 142 | function makeDelegateCall(uint _value) public { 143 | a.delegatecall( 144 | abi.encodePacked(bytes4(keccak256("setValue(uint)")), _value) 145 | ); // Value of A is modified 146 | } 147 | } 148 | 149 | contract B { 150 | uint value; 151 | address public sender; 152 | function setValue(uint _value) public { 153 | value = _value; 154 | sender = msg.sender; // msg.sender is preserved in delegatecall. It was not available in callcode. 155 | } 156 | } 157 | ``` 158 | 159 | > gas() option is available for call, callcode and delegatecall. value() option is not supported for delegatecall. 160 | 161 | #### callcode 162 | - `
.callcode(...) returns (bool)`: issue low-level CALLCODE, returns false on failure 163 | 164 | > Prior to homestead, only a limited variant called `callcode` was available that did not provide access to the original `msg.sender` and `msg.value` values. 165 | 166 | ### Array 167 | 168 | Arrays can be dynamic or have a fixed size. 169 | 170 | ```solidity 171 | uint[] dynamicSizeArray; 172 | 173 | uint[7] fixedSizeArray; 174 | ``` 175 | 176 | ### Fixed byte arrays 177 | 178 | `bytes1(byte)`, `bytes2`, `bytes3`, ..., `bytes32`. 179 | 180 | Operators: 181 | 182 | Comparisons: `<=`, `<`, `==`, `!=`, `>=`, `>` (evaluate to bool) 183 | Bit operators: `&`, `|`, `^` (bitwise exclusive or), `~` (bitwise negation), `<<` (left shift), `>>` (right shift) 184 | Index access: If x is of type bytesI, then x[k] for 0 <= k < I returns the k th byte (read-only). 185 | 186 | Members 187 | 188 | - `.length` : read-only 189 | 190 | ### Dynamic byte arrays 191 | 192 | `bytes`: Dynamically-sized `byte` array. It is similar to `byte[]`, but it is packed tightly in calldata. Not a value-type! 193 | 194 | `string`: Dynamically-sized UTF-8-encoded string. It is equal to `bytes` but does not allow length or index access. Not a value-type! 195 | 196 | ### Enum 197 | 198 | Enum works just like in every other language. 199 | 200 | ```solidity 201 | enum ActionChoices { 202 | GoLeft, 203 | GoRight, 204 | GoStraight, 205 | SitStill 206 | } 207 | 208 | ActionChoices choice = ActionChoices.GoStraight; 209 | ``` 210 | 211 | ### Struct 212 | 213 | New types can be declared using struct. 214 | 215 | ```solidity 216 | struct Funder { 217 | address addr; 218 | uint amount; 219 | } 220 | 221 | Funder funders; 222 | ``` 223 | 224 | ### Mapping 225 | 226 | Declared as `mapping(_KeyType => _ValueType)` 227 | 228 | Mappings can be seen as **hash tables** which are virtually initialized such that every possible key exists and is mapped to a value. 229 | 230 | **key** can be almost any type except for a mapping, a dynamically sized array, a contract, an enum, or a struct. **value** can actually be any type, including mappings. 231 | 232 | 233 | ## Control Structures 234 | 235 | Most of the control structures from JavaScript are available in Solidity except for `switch` and `goto`. 236 | 237 | - `if` `else` 238 | - `while` 239 | - `do` 240 | - `for` 241 | - `break` 242 | - `continue` 243 | - `return` 244 | - `? :` 245 | 246 | ## Functions 247 | 248 | ### Structure 249 | 250 | `function () {internal|external|public|private} [pure|constant|view|payable] [returns ()]` 251 | 252 | ### Access modifiers 253 | 254 | - ```public``` - Accessible from this contract, inherited contracts and externally 255 | - ```private``` - Accessible only from this contract 256 | - ```internal``` - Accessible only from this contract and contracts inheriting from it 257 | - ```external``` - Cannot be accessed internally, only externally. Recommended to reduce gas. Access internally with `this.f`. 258 | 259 | ### Parameters 260 | 261 | #### Input parameters 262 | 263 | Parameters are declared just like variables and are `memory` variables. 264 | 265 | ```solidity 266 | function f(uint _a, uint _b) {} 267 | ``` 268 | 269 | #### Output parameters 270 | 271 | Output parameters are declared after the `returns` keyword 272 | 273 | ```solidity 274 | function f(uint _a, uint _b) returns (uint _sum) { 275 | _sum = _a + _b; 276 | } 277 | ``` 278 | 279 | Output can also be specified using `return` statement. In that case, we can omit parameter name `returns (uint)`. 280 | 281 | Multiple return types are possible with `return (v0, v1, ..., vn)`. 282 | 283 | 284 | ### Constructor 285 | 286 | Function that is executed during contract deployment. Defined using the `constructor` keyword. 287 | 288 | ```solidity 289 | contract C { 290 | address owner; 291 | uint status; 292 | constructor(uint _status) { 293 | owner = msg.sender; 294 | status = _status; 295 | } 296 | } 297 | ``` 298 | 299 | ### Function Calls 300 | 301 | #### Internal Function Calls 302 | 303 | Functions of the current contract can be called directly (internally - via jumps) and also recursively 304 | 305 | ```solidity 306 | contract C { 307 | function funA() returns (uint) { 308 | return 5; 309 | } 310 | 311 | function FunB(uint _a) returns (uint ret) { 312 | return funA() + _a; 313 | } 314 | } 315 | ``` 316 | 317 | #### External Function Calls 318 | 319 | `this.g(8);` and `c.g(2);` (where c is a contract instance) are also valid function calls, but, the function will be called “externally”, via a message call. 320 | 321 | > `.gas()` and `.value()` can also be used with external function calls. 322 | 323 | #### Named Calls 324 | 325 | Function call arguments can also be given by name in any order as below. 326 | 327 | ```solidity 328 | function f(uint a, uint b) { } 329 | 330 | function g() { 331 | f({b: 1, a: 2}); 332 | } 333 | ``` 334 | 335 | #### Unnamed function parameters 336 | 337 | Parameters will be present on the stack, but are not accessible. 338 | 339 | ```solidity 340 | function f(uint a, uint) returns (uint) { 341 | return a; 342 | } 343 | ``` 344 | 345 | ### Function type 346 | 347 | Pass function as a parameter to another function. Similar to `callbacks` and `delegates` 348 | 349 | ```solidity 350 | pragma solidity ^0.4.18; 351 | 352 | contract Oracle { 353 | struct Request { 354 | bytes data; 355 | function(bytes memory) external callback; 356 | } 357 | Request[] requests; 358 | event NewRequest(uint); 359 | function query(bytes data, function(bytes memory) external callback) { 360 | requests.push(Request(data, callback)); 361 | NewRequest(requests.length - 1); 362 | } 363 | function reply(uint requestID, bytes response) { 364 | // Here goes the check that the reply comes from a trusted source 365 | requests[requestID].callback(response); 366 | } 367 | } 368 | 369 | contract OracleUser { 370 | Oracle constant oracle = Oracle(0x1234567); // known contract 371 | function buySomething() { 372 | oracle.query("USD", this.oracleResponse); 373 | } 374 | function oracleResponse(bytes response) { 375 | require(msg.sender == address(oracle)); 376 | } 377 | } 378 | ``` 379 | 380 | 381 | ### Function Modifier 382 | 383 | Modifiers can automatically check a condition prior to executing the function. 384 | 385 | ```solidity 386 | modifier onlyOwner { 387 | require(msg.sender == owner); 388 | _; 389 | } 390 | 391 | function close() onlyOwner { 392 | selfdestruct(owner); 393 | } 394 | ``` 395 | 396 | ### View or Constant Functions 397 | 398 | Functions can be declared `view` or `constant` in which case they promise not to modify the state, but can read from them. 399 | 400 | ```solidity 401 | function f(uint a) view returns (uint) { 402 | return a * b; // where b is a storage variable 403 | } 404 | ``` 405 | 406 | > The compiler does not enforce yet that a `view` method is not modifying state. 407 | 408 | ### Pure Functions 409 | 410 | Functions can be declared `pure` in which case they promise not to read from or modify the state. 411 | 412 | ```solidity 413 | function f(uint a) pure returns (uint) { 414 | return a * 42; 415 | } 416 | ``` 417 | 418 | ### Payable Functions 419 | 420 | Functions that receive `Ether` are marked as `payable` function. 421 | 422 | ### Fallback Function 423 | 424 | A contract can have exactly one **unnamed function**. This function cannot have arguments and cannot return anything. It is executed on a call to the contract if none of the other functions match the given function identifier (or if no data was supplied at all). 425 | 426 | ```solidity 427 | function() { 428 | // Do something 429 | } 430 | ``` 431 | 432 | ## Contracts 433 | 434 | ### Creating contracts using `new` 435 | 436 | Contracts can be created from another contract using `new` keyword. The source of the contract has to be known in advance. 437 | 438 | ```solidity 439 | contract A { 440 | function add(uint _a, uint _b) returns (uint) { 441 | return _a + _b; 442 | } 443 | } 444 | 445 | contract C { 446 | address a; 447 | function f(uint _a) { 448 | a = new A(); 449 | } 450 | } 451 | ``` 452 | 453 | ### Contract Inheritance 454 | 455 | Solidity supports multiple inheritance and polymorphism. 456 | 457 | ```solidity 458 | contract owned { 459 | function owned() { owner = msg.sender; } 460 | address owner; 461 | } 462 | 463 | contract mortal is owned { 464 | function kill() { 465 | if (msg.sender == owner) selfdestruct(owner); 466 | } 467 | } 468 | 469 | contract final is mortal { 470 | function kill() { 471 | super.kill(); // Calls kill() of mortal. 472 | } 473 | } 474 | ``` 475 | 476 | #### Multiple inheritance 477 | 478 | ```solidity 479 | contract A {} 480 | contract B {} 481 | contract C is A, B {} 482 | ``` 483 | 484 | #### Constructor of base class 485 | 486 | ```solidity 487 | contract A { 488 | uint a; 489 | constructor(uint _a) { a = _a; } 490 | } 491 | 492 | contract B is A(1) { 493 | constructor(uint _b) A(_b) { 494 | } 495 | } 496 | ``` 497 | 498 | 499 | ### Abstract Contracts 500 | 501 | Contracts that contain implemented and non-implemented functions. Such contracts cannot be compiled, but they can be used as base contracts. 502 | 503 | ```solidity 504 | pragma solidity ^0.4.0; 505 | 506 | contract A { 507 | function C() returns (bytes32); 508 | } 509 | 510 | contract B is A { 511 | function C() returns (bytes32) { return "c"; } 512 | } 513 | ``` 514 | 515 | ## Interface 516 | 517 | `Interfaces` are similar to abstract contracts, but they have restrictions: 518 | 519 | - Cannot have any functions implemented. 520 | - Cannot inherit other contracts or interfaces. 521 | - Cannot define constructor. 522 | - Cannot define variables. 523 | - Cannot define structs. 524 | - Cannot define enums. 525 | 526 | ```solidity 527 | pragma solidity ^0.4.11; 528 | 529 | interface Token { 530 | function transfer(address recipient, uint amount); 531 | } 532 | ``` 533 | 534 | ## Events 535 | 536 | Events allow the convenient usage of the EVM logging facilities, which in turn can be used to “call” JavaScript callbacks in the user interface of a dapp, which listen for these events. 537 | 538 | Up to three parameters can receive the attribute indexed, which will cause the respective arguments to be searched for. 539 | 540 | > All non-indexed arguments will be stored in the data part of the log. 541 | 542 | ```solidity 543 | pragma solidity ^0.4.0; 544 | 545 | contract ClientReceipt { 546 | event Deposit( 547 | address indexed _from, 548 | bytes32 indexed _id, 549 | uint _value 550 | ); 551 | 552 | function deposit(bytes32 _id) payable { 553 | emit Deposit(msg.sender, _id, msg.value); 554 | } 555 | } 556 | ``` 557 | 558 | ## Library 559 | 560 | Libraries are similar to contracts, but they are deployed only once at a specific address, and their code is used with [`delegatecall`](#delegatecall) (`callcode`). 561 | 562 | ```solidity 563 | library arithmatic { 564 | function add(uint _a, uint _b) returns (uint) { 565 | return _a + _b; 566 | } 567 | } 568 | 569 | contract C { 570 | uint sum; 571 | 572 | function f() { 573 | sum = arithmatic.add(2, 3); 574 | } 575 | } 576 | ``` 577 | 578 | ## Using - For 579 | 580 | `using A for B;` can be used to attach library functions to any type. 581 | 582 | ```solidity 583 | library arithmatic { 584 | function add(uint _a, uint _b) returns (uint) { 585 | return _a + _b; 586 | } 587 | } 588 | 589 | contract C { 590 | using arithmatic for uint; 591 | 592 | uint sum; 593 | function f(uint _a) { 594 | sum = _a.add(3); 595 | } 596 | } 597 | ``` 598 | 599 | ## Error Handling 600 | 601 | - `assert(bool condition)`: throws if the condition is not met - to be used for internal errors. 602 | - `require(bool condition)`: throws if the condition is not met - to be used for errors in inputs or external components. 603 | - `revert()`: abort execution and revert state changes 604 | 605 | ```solidity 606 | function sendHalf(address addr) payable returns (uint balance) { 607 | require(msg.value % 2 == 0); // Only allow even numbers 608 | uint balanceBeforeTransfer = this.balance; 609 | addr.transfer(msg.value / 2); 610 | assert(this.balance == balanceBeforeTransfer - msg.value / 2); 611 | return this.balance; 612 | } 613 | ``` 614 | 615 | > Catching exceptions is not yet possible. 616 | 617 | ## Global variables 618 | 619 | ### Block variables 620 | 621 | - `block.blockhash(uint blockNumber) returns (bytes32)`: hash of the given block - only works for the 256 most recent blocks excluding current 622 | - `block.coinbase (address)`: current block miner’s address 623 | - `block.difficulty (uint)`: current block difficulty 624 | - `block.gaslimit (uint)`: current block gaslimit 625 | - `block.number (uint)`: current block number 626 | - `block.timestamp (uint)`: current block timestamp as seconds since unix epoch 627 | - `now (uint)`: current block timestamp (alias for `block.timestamp`) 628 | 629 | ### Transaction variables 630 | 631 | - `msg.data (bytes)`: complete calldata 632 | - `msg.gas (uint)`: remaining gas 633 | - `msg.sender (address)`: sender of the message (current call) 634 | - `msg.sig (bytes4)`: first four bytes of the calldata (i.e. function identifier) 635 | - `msg.value (uint)`: number of wei sent with the message 636 | - `tx.gasprice (uint)`: gas price of the transaction 637 | - `tx.origin (address)`: sender of the transaction (full call chain) 638 | 639 | ### Mathematical and Cryptographic Functions 640 | 641 | - `addmod(uint x, uint y, uint k) returns (uint)`: 642 | compute (x + y) % k where the addition is performed with arbitrary precision and does not wrap around at 2**256. 643 | - `mulmod(uint x, uint y, uint k) returns (uint)`: 644 | compute (x * y) % k where the multiplication is performed with arbitrary precision and does not wrap around at 2**256. 645 | - `keccak256(...) returns (bytes32)`: 646 | compute the Ethereum-SHA-3 (Keccak-256) hash of the (tightly packed) arguments 647 | - `sha256(...) returns (bytes32)`: 648 | compute the SHA-256 hash of the (tightly packed) arguments 649 | - `sha3(...) returns (bytes32)`: 650 | alias to keccak256 651 | - `ripemd160(...) returns (bytes20)`: 652 | compute RIPEMD-160 hash of the (tightly packed) arguments 653 | - `ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)`: 654 | recover the address associated with the public key from elliptic curve signature or return zero on error (example usage) 655 | 656 | ### Contract Related 657 | - `this (current contract’s type)`: the current contract, explicitly convertible to Address 658 | - `selfdestruct(address recipient)`: destroy the current contract, sending its funds to the given Address 659 | - `suicide(address recipient)`: alias to selfdestruct. Soon to be deprecated. 660 | 661 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /solidity-security.md: -------------------------------------------------------------------------------- 1 | ### WIP Version. Pending review. Use with caution 2 | 3 | # Solidity security guidelines & Best practices 4 | 5 | Solidity cheatsheet is available in [solidity-cheatsheet](/README.md). 6 | 7 | ## Tips & Tricks 8 | - Ethereum will be updated very frequently until a stable build. So expect new best practices and security consideration every now and then. 9 | - Your code will have bugs and be prepared to handle those. Use techniques such as pausing the contract and limiting usage. 10 | - Keep your contract simple and Modularize. 11 | - Make use of libraries so that you can reuse and update code. 12 | - Try to use already available tools and libraries and update them frquently. 13 | - Never try to store and implement everything in solidity. Use it where decentralization is needed. 14 | 15 | 16 | ### External calls 17 | 18 | Avoid using external calls whenever possible. Calls to untrusted code can lead to security flaw. When using external contract calls, assume that unsafe code might execute. Even if the contract is not malicious, malicious code can be executed by any contracts it calls. 19 | 20 | Use External calls at the bottom of the function as it will forward all the gas to the funtion. 21 | 22 | Use `
.call.gas(gasAmount)()` to limit sending gas to external calls. 23 | 24 | 25 | ### Sending transaction from contracts 26 | 27 | `
.send()` and `
.transfer()` are considered safe. It has a limited gas of `2300` which is low for any task except for an event. 28 | 29 | `
.transfer()` will revert the transaction and `
.send()` will return false. Use it based on requirement. 30 | 31 | ### Error handling 32 | 33 | Some functions will return false if it fails. Make sure to handle the possibility that the call will fail, by checking the return value. 34 | 35 | `call`, `callcode`, `delegatecall`, `send` are some functions that return `false` on failure. 36 | 37 | ``` 38 | // BAD 39 |
.send(10); 40 | 41 | // GOOD 42 | 43 | // Including success and failure callbaks 44 | if(
.send()) { 45 | // OnSuccess 46 | } else { 47 | // OnFail 48 | } 49 | 50 | // Using assert that will revert the transaction on false 51 | assert(
.send()) 52 | ``` 53 | 54 | ### Using access modifiers 55 | 56 | Use access modifiers explicitly. Using `external` for external only function will reduce gas. 57 | 58 | ``` 59 | // BAD 60 | function externalFunction() { 61 | // Do Something 62 | } 63 | 64 | // GOOD 65 | uint public status; 66 | function externalFunction() external { 67 | // Do Something 68 | } 69 | ``` 70 | 71 | ### Make use of function modifiers 72 | 73 | Use modifiers to restrict access to functions. Avoid unauthorized access for all functions. You should use `msg.sender` over `tx.origin` for authorization. 74 | 75 | ``` 76 | // BAD 77 | function selfdestruct() { 78 | selfdestruct(
); 79 | } 80 | 81 | // GOOD 82 | modifier onlyOwner() { 83 | require(msg.sender ==
); 84 | _ 85 | } 86 | function selfdestruct() onlyOwner { 87 | selfdestruct(
); 88 | } 89 | ``` 90 | 91 | ### Upgrading contracts 92 | 93 | Use `delegatecall` in a proxy contract for upgrading contracts overtime. 94 | --------------------------------------------------------------------------------