{"id":15065153,"url":"https://github.com/mtumilowicz/solidity-basics-workshop","last_synced_at":"2026-01-02T08:20:54.243Z","repository":{"id":197480266,"uuid":"695688639","full_name":"mtumilowicz/solidity-basics-workshop","owner":"mtumilowicz","description":"Introduction to smart contract, Solidity language and ethereum ecosystem.","archived":false,"fork":false,"pushed_at":"2023-10-27T09:29:09.000Z","size":241,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-22T12:49:21.726Z","etag":null,"topics":["blockchain","blockchain-technology","cryptocurrency","ethereum","ethereum-blockchain","ethereum-contract","ethereum-contracts","ethereum-smart-contract","ethereum-virtual-machine","smart-contract","smart-contracts","solidity","solidity-contracts","solidity-language","workshop","workshop-materials","workshops"],"latest_commit_sha":null,"homepage":"","language":"Solidity","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mtumilowicz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-09-23T22:45:52.000Z","updated_at":"2023-10-27T12:01:54.000Z","dependencies_parsed_at":"2023-10-27T10:57:45.754Z","dependency_job_id":null,"html_url":"https://github.com/mtumilowicz/solidity-basics-workshop","commit_stats":null,"previous_names":["mtumilowicz/solidity-basics-event-ticketing-app-workshop","mtumilowicz/solidity-basics-workshop"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fsolidity-basics-workshop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fsolidity-basics-workshop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fsolidity-basics-workshop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fsolidity-basics-workshop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mtumilowicz","download_url":"https://codeload.github.com/mtumilowicz/solidity-basics-workshop/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243806114,"owners_count":20350783,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blockchain","blockchain-technology","cryptocurrency","ethereum","ethereum-blockchain","ethereum-contract","ethereum-contracts","ethereum-smart-contract","ethereum-virtual-machine","smart-contract","smart-contracts","solidity","solidity-contracts","solidity-language","workshop","workshop-materials","workshops"],"created_at":"2024-09-25T00:34:45.512Z","updated_at":"2026-01-02T08:20:54.206Z","avatar_url":"https://github.com/mtumilowicz.png","language":"Solidity","funding_links":[],"categories":[],"sub_categories":[],"readme":"# solidity-basics-workshop\n\n* references\n    * https://www.oreilly.com/library/view/hands-on-smart-contract/9781492045250/\n    * https://www.amazon.com/Solidity-Programming-Essentials-building-contracts/dp/1803231181\n    * https://www.amazon.com/Beginning-Ethereum-Smart-Contracts-Programming/dp/1484292707\n    * https://www.springerprofessional.de/en/ethereum-smart-contract-development-in-solidity/18334966\n    * https://www.manning.com/books/blockchain-in-action\n    * https://www.packtpub.com/product/mastering-blockchain-programming-with-solidity/9781839218262\n    * https://www.algoexpert.io/blockchain/index\n    * https://chat.openai.com\n    * https://www.investopedia.com/terms/b/basic-attention-token.asp\n    * https://medium.com/@danielyamagata/understand-evm-opcodes-write-better-smart-contracts-e64f017b619\n    * https://ethereum.stackexchange.com/questions/117100/why-do-many-solidity-projects-prefer-importing-specific-names-over-whole-modules\n    * https://medium.com/@eiki1212/what-is-ethereum-gas-simple-explanation-2f0ae62ed69c\n    * https://ethereum.stackexchange.com/questions/38387/contract-address-transfer-method-gas-cost\n    * https://medium.com/@natelapinski/the-difference-between-tx-origin-60737d3b3ab5\n    * https://ethereum.stackexchange.com/questions/21448/how-to-get-a-contracts-balance-in-solidity\n    * https://medium.com/@blockchain101/solidity-bytecode-and-opcode-basics-672e9b1a88c2\n    * https://medium.com/coinmonks/solidity-storage-vs-memory-vs-calldata-8c7e8c38bce\n    * https://ethereum.stackexchange.com/questions/123169/can-calldata-be-used-in-every-function-visibility\n    * https://ethereum.stackexchange.com/questions/74442/when-should-i-use-calldata-and-when-should-i-use-memory\n    * https://ethereum.stackexchange.com/questions/117770/how-to-use-calldata-return-values-in-solidity-and-when-are-they-useful\n    * https://ethereum.stackexchange.com/questions/64108/whats-the-difference-between-address-and-address-payable\n    * https://docs.soliditylang.org/\n    * https://medium.com/soonami/3-secure-alternative-methods-to-replace-tx-origin-for-solidity-developers-4acc2c49e1c\n    * https://ethereum.stackexchange.com/questions/82240/what-is-the-immutable-keyword-in-solidity\n    * https://coinsbench.com/solidity-layout-and-access-of-storage-variables-simply-explained-1ce964d7c738\n    * https://consensys.github.io/smart-contract-best-practices/development-recommendations/solidity-specific/assert-require-revert\n    * https://stackoverflow.com/questions/71502322/difference-between-assert-and-require\n    * https://stackoverflow.com/questions/70216805/why-assertion-is-used-on-this-smart-contract\n    * https://ethereum.stackexchange.com/questions/15166/difference-between-require-and-assert-and-the-difference-between-revert-and-thro\n    * https://medium.com/coinmonks/error-handling-in-solidity-pt-4-ce2fef14ceb2\n    * https://medium.com/@solidity101/writing-robust-smart-contracts-with-require-assert-and-revert-in-solidity-a997f6c9b13f\n    * https://medium.com/coinmonks/solidity-fundamentals-a95bb6c8ba2a\n    * https://thekscar.medium.com/writing-solidity-unit-tests-for-testing-assert-require-and-revert-conditions-using-truffle-2e182d91a40f\n    * https://medium.com/coinmonks/learn-solidity-lesson-26-error-handling-ccf350bc9374\n    * https://ethereum.stackexchange.com/questions/131384/is-msg-sender-reliable-in-view-and-pure-functions\n    * https://www.alchemy.com/overviews/solidity-gas-optimization\n    * https://medium.com/coinmonks/ethereum-data-transaction-receipt-trie-and-logs-simplified-30e3ae8dc3cf\n    * https://medium.com/cryptronics/ethereum-smart-contract-security-73b0ede73fa8\n    * https://medium.com/what-is-infura/what-is-infura-59dbdd778455\n    * https://ethereum.stackexchange.com/questions/6897/what-is-the-difference-between-truffle-and-remix\n    * https://remix-ide.readthedocs.io/en/latest/unittesting.html#customization\n\n## preface\n* goals of this workshop\n    * understanding memory model of emv\n    * introduction to smart contract\n    * basics of Solidity programming\n    * introduction to Remix: https://remix.ethereum.org\n* workshop task\n    * implement event ticketing smart contract\n        * `createTicket(qrCode)`\n            * `qrCode` is link to IPFS\n        * `buyTicket(ticketId)`\n        * `verifyTicket(ticketId)`\n            * assume that ticketId is derived from `qrCode` by other system \n        * `getQRCode(ticketId)`\n    * implement tests in solidity\n        * providing ethers to test\n            ```\n            /// #value: 10\n            function test() public payable { \n                Assert.equal(msg.value, 10, ...);\n            }\n            ```\n        * defining sender for the test\n            ```\n            import \"remix_accounts.sol\"; // must be imported in your test file to use custom sender\n          \n            /// #sender: account-0\n            function test() public payable {\n              Assert.equal(msg.sender, TestsAccounts.getAccount(0), ...);\n            }\n            ```\n        * check for exceptions\n            ```\n            function test() public {\n              try methodToTest {\n                Assert.ok(false, 'method execution should fail');\n              } catch Error(string memory reason) {\n                Assert.equal(reason, 'expected reason', 'failed with unexpected reason');\n              } catch (bytes memory /*lowLevelData*/) {\n                Assert.ok(false, 'failed unexpected');\n              }\n            }\n            ```\n\n## memory model\n1. storage\n    * permanent storage space\n        * stored on the blockchain\n    * where all state variables are stored\n    * each contract account has its own storage and can only access their own storage\n        * it is not possible to directly access the storage of another account\n        * each Ethereum account has its own unique address and associated storage\n            * this address is derived from the account's public key\n            * as a result, only the account owner has the private key necessary to access or modify the storage\n        * think of storage as a private database\n    * thinking of the storage as an array will help us understand it better\n        * each space in this storage \"array\" is called a slot and holds `32` bytes of data (`256 bits`)\n        * maximum length of this storage \"array\" is `2²⁵⁶-1`\n        * each slot can be occupied by more than one type\n            * unless sum of bytes are \u003c= 32\n            * so order matters\n        * example\n            ```\n            // SPDX-License-Identifier: MIT\n            pragma solidity ^0.8.16;\n\n            contract StorageLayout {\n                uint64 public value1 = 1;\n                uint64 public value2 = 2;\n                uint64 public value3 = 3; // order matters: you will need 3 slots if value3 and value5 are swapped\n                uint64 public value4 = 4;\n                uint256 public value5 = 5;\n            }\n            ```\n            and we can get storage at specific slot\n            ```\n            web3.eth.getStorageAt(\"0x9168fBa74ADA0EB1DA81b8E9AeB88b083b42eBB4\", 0)\n            // returns: `0x04000000000000000300000000000000020000000000000001`\n            // so we have value1, ..., value4 in one slot\n            web3.eth.getStorageAt(\"0x9168fBa74ADA0EB1DA81b8E9AeB88b083b42eBB4\", 1)\n            // returns: `0x0000000000000000000000000000000000000000000000000000000000000005`\n            ```\n        * dynamic arrays and structs always occupy a new slot\n            * any variables following them will also be initialized to start a new storage slot\n    * it is not cheap in terms of gas - so we need to optimize the use of storage\n        ```\n        contract storageExample {\n        uint256 sumOfArray;\n\n            function inefficientSum(uint256 [] memory _array) public {\n                    for(uint256 i; i \u003c _array.length; i++) {\n                        sumOfArray += _array[i]; // writing directly to storage\n                    }\n            }\n\n            function efficientSum(uint256 [] memory _array) public {\n               uint256 tempVar;\n\n               for(uint256 i; i \u003c _array.length; i++) {\n                        tempVar += _array[i]; // using temporary memory variable\n                    }\n               sumOfArray = tempVar;\n            }\n        }\n        ```\n    * Solidity does not have null values\n        * not assigning a value to a state variable = assigning its default value based on the type\n        * example\n            * `address` -\u003e `0x0000000000000000000000000000000000000000`\n            * enums -\u003e assigned the first value (index 0)\n1. memory\n    * works similarly to the memory of a computer, more specifically, the RAM (Random Access Memory)\n        * idea of RAM is that information can be read and stored in specific places\n        (at a particular memory address) and not just sequentially\n    * short-lived\n        * reserved for variables that are defined within the scope of a function\n        * gets torn down when a function completes its execution\n1. stack\n    * works on the LIFO (Last-In First-Out) scheme\n    * when the bytecode starts executing, the Stack is empty\n    * 1,024 levels deep in the EVM\n        * if it stores anything more than this, it raises an exception\n1. calldata\n    * it is a read-only location\n        * example\n            ```\n            contract Storage {\n\n                string[] messages;\n\n                function retrieve(uint index) public view returns (string calldata){\n                    return messages[index]; // not compiling\n                }\n            }\n            ```\n            * for it to work: need to copy string to the calldata area\n                * impossible: calldata is immutable\n            * however: if you already have something in calldata though, you can return it\n                * calldata can be returned from functions\n        * can typically only be used with functions that have external visibility\n            * source of these arguments needs to come from message calldata\n            * example: passing forward calldata arguments\n    * usually the signature of the function to be executed, followed by the ABI encoding of the function arguments\n        * can be verified in Remix, under smart contract method you can \"Copy calldata to clipboard\"\n        * example\n            * keccak256 online: https://emn178.github.io/online-tools/keccak_256.html\n            * function: `function createTicket(string)`\n                * `6897082f779ee6aa6c305e01892e057838143a4691bda17d4092e228fc6d147a`\n                * selector: `0x6897082f`\n            * argument: `c`\n                * `0x63`\n                * prepending the data length: `0x0163`\n                * we need to zero-pad to a 32-byte word\n            * calldata: `concat(selector, packedPaddedArgument)`\n    * temporary location where function arguments are stored\n    * avoids unnecessary copies and ensures that the data is unaltered\n    * helps lower gas consumption\n        * compiler can skip ABI encoding\n            * the data is already formatted correctly according to the ABI\n            * for memory: Solidity would need to encode it before returning\n    * calldata is allocated by the caller, while memory is allocated by the callee\n* assignments will either result in copies being created, or mere references to the same piece of data\n    * between storage and memory/calldata - always create a separate copy\n    * from memory to memory\n        * create a new copy for value types\n        * create references for reference types\n            * changing one memory variable alters all other memory variables that refer to the same data\n    * from storage to storage\n        * assign a reference\n\n## tools\n* infura\n    * is a kind of node storage (cluster)\n    * set of tools that provides its services for integrating your application with the Ethereum network\n    * you do not need to run your local blockchain for the mainnet and testnets\n        * example: MetaMask internally uses an Infura link to connect to the Ethereum blockchain\n    * also host the Inter Planetary File System (IPFS) nodes and the IPFS public gateway\n* Truffle\n    * development environment/framework for smart contracts\n    * can be included in projects as a build dependency\n* Remix\n    * IDE in the browser\n* linters\n    * analyze the given source code and report programming errors, bugs, and stylistic errors\n    * two commonly used linter tools available\n        * solhint - provides security and style guideline-specific validations\n        * ethlint -  similar to solhint\n* solidity-coverage\n    * ode coverage tool specifically designed for Solidity smart contracts\n\n## smart contract\n* example: https://etherscan.io/address/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\n    * without verification there’s no way to guarantee it matches the code in the blockchain (and we tried a number of combinations)\n    * in general, code should be posted on Etherscan (not just Github)\n* program (bytecode) deployed and executed in the Ethereum Virtual Machine (EVM)\n* stored on the Ethereum blockchain\n* stores information in blockchain in two distinct ways\n    * account storage\n        * contains any data that defines the smart contract state and that the contract can access\n    * logs\n        * store information that is not required by the contract but must be accessed by other off chain applications\n            * example: front-end, analytics etc\n        * much cheaper than account storage\n    * overview\n        ![alt text](img/block_organisation.webp)\n    * example: non fungible tokens\n        * account storage: token Ownership\n            * contract needs it to prove ownership and provide ownership transfer functionality\n        * logs\n            * token ownership history\n                * contract only needs to be aware of current token ownership\n                * tracking a token’s ownership history is interest to investors or decision makers\n            * UI notifications\n                * transactions are asynchronous, the smart contract cannot return value to the front end\n                * when the mint occurs, it could write it to the log\n                    * front end could then listen for notifications and display them to the user\n            * off chain triggers\n                * when you want to transfer your token to another blockchain\n                    * example: play a game built on a different blockchain\n                    * initiate a transfer to a common gateway, and the transaction will log the transfer\n                    * common gateway would then pick that information and mint a corresponding token in the other chain\n* written in a specific programming language\n    * example: Solidity, Vyper\n* self-executing with the terms of the agreement written directly into code\n    * automate processes\n        * Token Sales (ICO)\n            * can distribute tokens to contributors based on predefined conditions\n    * enforce rules\n        * Supply Chain Verification\n            * can validate products' authenticity based on information stored\n            on the blockchain (e.g., origin, certifications), ensuring compliance with predefined standards\n    * facilitate transactions\n        * Royalty Payments for Creators\n            * when revenue is generated from the sale or use of content (e.g., music, art), the smart\n            contract automatically distributes the earnings to the creators according to the agreed-upon terms\n* ability to create DApps = Decentralized Application\n    * example\n        * decentralized exchange (DEX): https://uniswap.org\n            * allows users to trade cryptocurrencies directly with one another without the need for\n            an intermediary or centralized authority\n            * instead of relying on order books (as in traditional exchanges) uses liquidity pools and smart\n            contracts to facilitate trading\n        * NFT game: https://www.cryptokitties.co\n    * application that runs on a decentralized network of computers (usually a blockchain)\n        * transactions and data stored in a DApp are recorded on a blockchain\n        * not controlled by a single entity\n    * components:\n        * backend\n            * smart contract (open sourced)\n            * user's cryptocurrency wallet\n                * used to manage and control the user's assets within the DApp\n        * frontend: GUI user-facing part of the DApp\n            * responsible for communicating with the smart contracts on the blockchain\n    * often have their own native tokens or cryptocurrencies\n        * used to incentivize network participants and can represent various forms of value\n        * example: BAT (Basic Attention Token)\n            * system for tracking media consumers' time and attention on websites using the Brave web browser\n            * its goal is to efficiently distribute advertising money between advertisers, publishers, and\n            readers of online marketing content and ads\n    * can operate autonomously without the need for intermediaries\n\n## syntax\n* example\n    ```\n    import 'CommonLibrary.sol';\n\n    pragma solidity ^0.8.9;\n\n    contract FirstContract { }\n    ```\n* `pragma`\n    * generally the first line of code within any Solidity file\n    * specifies the target compiler version\n    * `^`: contract will compile for any version above the version mentioned but less than the next major version\n        * example: `0.8.9` will not work with the `0.9.x` compiler version, but lesser than it\n    * good practice: compile Solidity code with an exact compiler version rather than using `^`\n* `import`\n    * example\n        ```\n        import {\n            ERC721HolderUpgradeable // way to avoid naming conflicts\n        } from \"@openzeppelin/contracts-upgradeable/token/ERC721/utils/ERC721HolderUpgradeable.sol\";\n        ```\n    * are for your development environment only\n        * when you deploy your contracts on the Ethereum blockchain, import statements must be replaced with the actual content of the `.sol` file that you imported\n        * Ethereum blockchain takes the flattened files of the smart contract and deploys it\n            * content of the imported contract is effectively copied and pasted into the current contract during the compilation process\n            * this means that all elements defined in the imported contract become part of the current contract\n        * framework, such as Truffle or the Remix IDE, converts all import statements and makes a single flattened contract during deployment\n* constructors\n    * are optional and the compiler induces a default constructor when none is explicitly defined\n    * executed once while deploying the contract\n    * can have a payable attribute\n        * enable it to accept Ether during deployment and contract instance creation time\n    * can be defined as internal\n        * contract cannot be deployed\n* two ways of creating a contract\n    * using the new keyword\n        * deploys and creates a new contract instance\n            * when we deploy the contract, we simply deploy compiled hexadecimals under the data field\n                * example\n                    ```\n                    pragma solidity ^0.8.21;\n\n                    contract MyContract {\n\n                    }\n                    ```\n                    is compiled to\n                    ```\n                    0x6080604052348015600e575f80fd5b50603e80601a5f395ff3fe60806040525f80fdfea2646970667358221220e48937f3cf7fd35ec1550eb34b94a85d69119e8fe5c9a996d43a65140f5ce75964736f6c63430008150033\n                    ```\n        * example: `HelloWorld myObj = new HelloWorld();`\n    * using the address of the already-deployed contract\n        * is used when a contract is already deployed and instantiated\n        * example: `HelloWorld myObj = HelloWorld(address);`\n* this\n    * represents the current contract\n    * use case: get balance of current contract\n        ```\n        address(this).balance\n        ```\n* inheritance\n    * C3 linearization / Method Resolution Order (MRO) (similar to Python)\n        * force a specific order in graphs of base contracts\n    * contract becomes an abstract contract when it consists of functions without any implementation\n        * you cannot create an instance of an abstract contract.\n    * interfaces cannot contain any definitions and any state variables\n        * only the signature of functions\n* types\n    * bool\n    * uint/int8...256\n        * example: uint8 - unsigned integer with 8 bits (ranging from 0 to 255)\n        * uint/int - alias for uint256/int256\n        * signed integers - hold both negative and positive values\n        * unsigned integers - hold positive values along with zero\n    * arrays\n        * fixed arrays\n            ```\n            int[5] age = [int(10), 20, 30, 40, 50];\n\n            age[0]; // retrieve\n            ```\n            * slot storage\n                * stored contiguously\n        * dynamic arrays\n            ```\n            int[] age = [int(10), 20, 30, 40, 50];\n            int[] age = new int[](5);\n\n            age.push(60); // add\n            age.pop(); // remove\n            age[0]; // retrieve\n            ```\n            * slot storage\n                * in the slot: only its length is saved\n                    * its elements stored somewhere else in the storage\n                * example\n                    ```\n                    uint256[] public values = [1,2,3,4,5,6,7,8];\n                    uint constant slot = 0\n                    uint constant startingIndexOfValues = keccak256(abi.encode(slot))\n\n                    function getElementIndexInStorage(uint256 _elementIndex) public pure returns(bytes32) {\n                        return bytes32(uint256(startingIndexOfValues) + _elementIndex);\n                    }\n                    ```\n                * elements are stored sequentially from the hash\n                    * space layout applies to them\n                    * example: many elements of `uint8[]` would fit in a single slot until 32 bytes are occupied\n                * indices are huge and look random\n                    * keccak256 returns a 256 bit number\n                    * storage capacity is 2²⁵⁶-1 elements\n                        * we are good and in range using keccak256 hash as slot index\n                    * makes the probability of 2 or more different state variables sharing the same slot in storage low\n    * bytes\n        * bytes1 to bytes32 inclusive\n        * fixed-size byte array\n        * example\n            ```\n            function test() public pure returns (bytes1) {\n                bytes2 arr = 0x1234;\n                bytes1 first = arr[0]; // 0x12\n                bytes1 second = arr[0]; // 0x34\n                return first;\n            }\n            ```\n    * String\n        * do not provide string manipulation methods\n            * no access by indexed\n            * no push\n            * no length property\n            * to perform any of these - convert into bytes\n                ```\n                bytes byteName = bytes(name);\n                ```\n            * no equals\n                ```\n                Keccak256(''hello world'') == keccak256(''hello world'') // check for equality\n                ```\n        * slot storage\n            * same as fixed arrays\n    * Bytes\n        * similar to dynamic arrays\n    * address\n        * one of the most used data types in smart contracts\n        * provides three functions\n            * call\n            * delegatecall\n            * callcode\n            * described here: https://github.com/mtumilowicz/solidity-assembly-proxy-workshop\n        * single property: balance\n        * designed to hold account addresses in Ethereum\n            * 160 bits or 20 bytes in size\n        * cannot be used to send or receive Ethers\n            * can be converted to `payable address`\n                ```\n                address addr1 = msg.sender;\n                address payable addr3 = payable(addr1);\n                ```\n        * payable\n            * superset of the address type\n                * idea behind this distinction: you are not supposed to send Ether to a plain address\n                    * example: it might be a smart contract that was not built to accept Ether\n            * additional capability of receiving as well as sending Ether to other accounts\n            * additional methods used to send ether to a contract or an externally owned account\n                * transfer/send()\n                    * provides 2,300 units of gas as a fixed limit (cannot be superseded)\n                        * currently only enough to log an event\n                    * low-level functions and should be used with caution\n                        * if used with the contract address, it will invoke a fallback or receive function on the contract\n                            * may recursively call back within the calling contract again and again (reentrancy attack)\n                    * `send()` function returns Boolean\n                    * `transfer()` raises an exception in the case of execution failure\n                        * all changes are reverted\n                        * better alternative to `send()`\n    * mapping\n        * similar to hash tables or dictionaries in other languages\n        * example\n            ```\n            mapping(address =\u003e uint256) public balances;\n\n            function setBalance(address _address, uint256 _balance) public {\n                balances[_address] = _balance;\n            }\n\n            function getBalance(address _address) public view returns (uint256) {\n                return balances[_address];\n            }\n            ```\n        * only as a storage type\n            * not stored sequentially as arrays\n                * there is no way to order them to save space by fitting smaller types into a single slot\n            * slot where the mapping is declared does not contain any information\n                * just empty bytes\n            * example\n                ```\n                mapping(address =\u003e uint256) public balances;\n                ```\n                and we need to know storage index of the `0x6827b8f6cc60497d9bf5210d602C0EcaFDF7C405`\n                1. left pad the address to 32 bytes\n                1. left pad the mapping index\n                    * our mapping is declared at index 0 of the storage\n                1. concatenate them and calculate the keccak256 hash for it\n        * Solidity does not allow iteration through mapping\n            * `OpenZeppelin` provides `EnumerableMap` that allows you to create an iterable mapping in Solidity\n        * possible to have nested mapping\n    * enum\n        * example\n            ```\n            enum Status { Inactive, Active, Paused }\n\n            function getStatus() public pure returns (Status) {\n                return Status.Active;\n            }\n            ```\n        * values are not directly visible outside the contract\n            * each enum value is assigned a unique consecutive integer value starting from 0\n            * if you externally call `getStatus()` you will get int: `1`\n    * struct\n        * help implement custom user-defined data types\n        * do not contain any logic within them\n        * slot storage\n            * slot index where it is declared is reserved for the first value it has\n                * and then sequentially\n                * example\n                    ```\n                    Person public p = Person(1, \"Jeremy\", 28, true);\n                    ```\n                    * id - slot index 0, name - slot index 1 and so on\n* global variables\n    * information about the current transaction and blocks\n    * `msg`\n        * `msg.value`\n            * amount of Ether (in wei) sent with the current transaction\n        * `msg.gas`\n            * amount of gas remaining in the current transaction\n        * `msg.data`\n            * contains the complete calldata\n            * data payload of the transaction\n            * contains the function selector and any input data provided when a function is called\n                * when contract is deployed, constructor selector is used\n        * `msg.sig`\n            * first four bytes of the `msg.data` (function selector)\n                * all of the public and external functions have special members available, called selector\n                    * returns the first 4 bytes of the function signature as bytes4\n                    * example\n                        ```\n                        function add(uint256 a, uint256 b) public pure returns (uint256);\n\n                        bytes4 functionSelector = bytes4(keccak256(\"add(uint256,uint256)\"));\n\n                        bytes4 functionSelector = this.add.selector;\n                        ```\n            * helps to optimize gas usage by directly specifying the function to be executed\n                * rather than parsing `msg.data` manually\n        * `msg.sender`\n            * represents the address that is currently calling or interacting with the smart contract\n    * `tx.origin`\n        * address of the original sender of the transaction\n            * EOA that initiated the transaction\n            * EOAs are the only things in Ethereum that could create a transaction\n                * can change with ERC-4337 (account abstraction), whereby certain smart contracts will have the\n                ability to issue transactions on behalf of a user\n        * `msg.sender` is not always equal to `tx.origin`\n            * smart contract can call other smart contracts as part of the same transaction\n            * each time a contract calls another contract, the value of `msg.sender` is updated\n    * `block.timestamp`\n        * timestamp of the current block as a Unix timestamp\n        * generated by the miners\n        * no contract should rely on the block timestamp for critical operations\n           * in particular: should not use it as a seed for random number generation\n           * Consensys give a 15-seconds rule in their guidelines\n              * it is safe to use block.timestamp, if your time depending code can deal with a 15 seconds time variation\n* cryptographic functions for hashing values\n    * SHA2 (sha256)\n    * SHA3 (sha3 or keccak256 function)\n        * recommended to use the keccak256 function for hashing needs\n            * is specified in the Ethereum Yellow Paper\n            * using sha256 could potentially lead to confusion and compatibility issues\n* qualifiers\n    * state variables\n        * internal\n            * default\n            * can only be used within current contract functions and any contract that inherits from it\n            * cannot be directly accessed by external contracts or external actors, its value is still\n            stored on the blockchain and can be observed by inspecting the blockchain's state\n        * private\n            * can only be used in contracts containing them\n            * cannot be directly accessed by external contracts or external actors, its value is still\n            stored on the blockchain and can be observed by inspecting the blockchain's state\n        * public\n            * enables external access to state variables\n            * Solidity compiler generates a getter function for each public state variable\n            * cannot be directly modified from an externally owned account (EOA) - you need a setter method\n        * constant\n            * makes state variables immutable\n            * the compiler will replace references of this variable everywhere in code with the assigned value\n            * does not occupy storage on the blockchain\n        * immutable\n            * can only be assigned once\n            * read-only, but assignable in the constructor\n            * less restricted than those declared as constant\n    * functions\n        * internal - same as for state\n        * public - same as for state\n        * private - same as for state\n        * external\n            * can only be invoked by other contracts or externally owned accounts (EOAs)\n            * become part of the contract's interface\n            * helps to enforce security and transparency in your contract design\n        * additional qualifiers\n            * view\n                * not modify the state of the contract\n                    * state changing actions\n                        * writing to state variables\n                        * emitting events\n                        * creating other contracts\n                        * using selfdestruct\n                        * sending ether via send and transfer\n                        * calling any function not marked view or pure\n                        * using low-level calls\n                        * using inline assembly that contains certain opcodes\n                * read-only\n                * view functions are accessible both off-chain and on-chain\n                    * on-chain\n                        * consumes gas\n                        * example: if function that changes the contract state calls a view function\n                    * off-chain\n                        * doesn't consume any gas\n            * pure\n                * more restrictive than `view`\n                    * cannot access state variables\n            * no way to fully trust `msg.sender` in a view or pure function\n                * signatures are not verified in simple calls\n                * one way to fully assure yourself of who is calling a function: to have the caller sign and message\n                and then use `ecrecover` to derive address from signature\n            * payable\n                * function can accept Ether only if marked as payable\n* modifiers\n    * is always associated with a function\n    * refers to a construct that changes the behavior of code under execution\n    * it has the power to change the behavior of functions that it is associated with\n    * is similar to the decorator pattern in object-oriented programming\n    * example\n        ```\n        modifier onlyOwner() {\n            require(msg.sender == owner, \"Only the owner can call this function\");\n            _; // This is a placeholder for the actual function code\n        }\n\n        function setData(uint256 _value) public onlyOwner {\n            data = _value;\n        }\n        ```\n* events\n    * transactions can generate events\n    * used to notify external systems about specific state changes\n        * example\n            ```\n            event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n            function transferNFT(address from, address to, uint256 tokenId) external {\n                require(_isApprovedOrOwner(msg.sender, tokenId), \"Not authorized\");\n                _safeTransfer(from, to, tokenId, \"\");\n\n                emit Transfer(from, to, tokenId);\n            }\n            ```\n    * stored in a special data structure called the \"logs bloom\"\n        * compact representation of all events emitted in a block\n        * allows nodes to quickly check if a log is included in a block, without having to go through the full log data\n        * smart contracts cannot hear events on their own because\n            * contract data lives in the States trie\n            * event data is stored in the Transaction Receipts trie\n        * digression: bloom filters\n            * problem: we want to find out if a user exists in a given list\n            * naive solution: go through the list\n                * if a list contains thousands of users, it becomes prohibitively expensive and extremely slow\n            * probabilistic solution: hashing and mapping each user in the list\n                ![alt text](img/bloom_filter_construction.webp)\n                ![alt text](img/bloom_filter_search.webp)\n            * is a probabilistic data structure that can either say “probably present” or “definitely not present”\n            * is extremely useful, especially when you expect the majority of the answers to be DEFINITELY NOT\n        * EVM combines the logs bloom of each transaction and creates a logs bloom in the header\n            * assume we have to search for the same query (tokens sold by a specific user) but across many blocks\n                * instead of querying the bloom of every transaction in every block, we can simply query the bloom at the header\n    * up to four indexed parameters (topics)\n        * used to filter events when querying the blockchain\n        * first topic is used to log the signature of the event\n            * the first four bytes of the keccak256 hash of the event's signature\n* error handling\n    * supports try-catch\n    * possibility to define error objects\n        * example\n            ```\n            error InsufficientBalance(uint available, uint required);\n            ```\n        * cannot be used in conjunction with the require function\n            * must be used in conjunction with the revert function\n    * revert\n        * example\n            ```\n            if (balanceOf[msg.sender] \u003c= 100) {\n                revert InsufficientBalance(balanceOf[msg.sender], 100);\n            }\n            ```\n        * use case\n            * if it is hard to use `require`\n                * example: complex ifs structures\n    * require\n        * using `if (!condition) revert(...)` and `require(condition, ...)` have the same effect\n        * example\n            ```\n            require(msg.value \u003e= price, \"Insufficient Ether sent\");\n            ```\n        * accepts two arguments\n            * condition that either evaluates to true or false\n            * optional error message\n                * string value that is returned to the caller as part of the exception reason\n                * returns an exception of the Error(string)\n        * if the evaluation of the statement is false then\n            * compiles to `0xfd` which is the `REVERT` opcode\n            * an exception is raised and execution is halted\n            * unused gas is returned to the caller\n                * does not return already-consumed gas\n                * should be used at the beginning of the function\n            * state change is reversed\n                * even if storage variables is made prior to the require statement (within a function)\n        * use cases - validations\n            * inputs\n            * return values\n            * calls to external contracts\n            * condition before state update\n        * correspond to function preconditions in other programming languages\n    * assert\n        * used to check for conditions that should never be false\n        * can't provide a message error\n        * use case\n            * test for internal errors\n                * example: checking the balance of an account after an operation\n            * check invariants\n                * example: the token to ether issuance ratio, in a token issuance contract, may be fixed\n                    * verify that this is the case at all times\n            * when you think that a current state has the potential to become inconsistent\n                * example: OpenZeppelin’s\n                    * SafeMath.add() function asserts that any summed integers do not overflow\n            * documenting your assumptions with assertions\n            * commonly employed during the development and testing stages to catch and identify bugs\n        * if the evaluation of the statement is false then\n            * compiles to `0xfd` which is the `REVERT` opcode\n                * uses revert with error signature Panic(uint256)\n                * till version 0.8.0\n                    * assert(false) compiled to `0xfe` - invalid opcode\n                        * using up all remaining gas\n                        * reverting all changes\n                * digression\n                    * non-critical errors revert either with empty error data or Error(string)\n                        * example: division by zero, failing assertions, array access out of bounds\n                    * critical errors revert with Panic(uint256)\n        * should often be combined with other techniques, such as pausing the contract and allowing upgrades\n            * otherwise, you may end up stuck, with an assertion that is always failing\n        * way to provide a target for formal verification\n            * example: tools such as the SMTChecker can detect bugs by trying to prove various statements about your code\n                * based on SMT (Satisfiability Modulo Theories) and Horn solving\n                * it considers require statements as assumptions and tries to prove that the conditions inside assert statements are always true\n                * if an assertion failure is found, a counterexample may be given to the user showing how the assertion can be violated\n                * if no warning is given by for a property, it means that the property is safe\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmtumilowicz%2Fsolidity-basics-workshop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmtumilowicz%2Fsolidity-basics-workshop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmtumilowicz%2Fsolidity-basics-workshop/lists"}