Last active
August 27, 2022 17:00
-
-
Save amithkk/383a8a2d34361f35f794277b08340c19 to your computer and use it in GitHub Desktop.
18 Steps to Solidity Fluency - based on Solidity By Example. Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.8.14+commit.80d49f37.js&optimize=false&runs=200&gist=
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENSED | |
pragma solidity ^0.8.13; // | |
contract HelloWorld { | |
// Variable declaration <datatype> <visibility> <name> = <initial-value> | |
string public hello = "Hello World!"; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENSED | |
// Storing data on ethereum is expensive! | |
// SLIDES AVAILABLE | |
// Types of Storage | |
// Storage - Permanent (Like your disk) | |
// Memory - Only when functions are executing (Like RAM) | |
// Calldata - Only for function parameters - NEEDED when calling into another contract from one contract | |
// Types of function | |
// One that creates a transaction (costs) | |
// One that only reads (free) | |
pragma solidity ^0.8.13; | |
contract SimpleStorage { | |
// State variable to store a number | |
uint public num; | |
string public str; | |
// You need to send a transaction to write to a state variable. | |
// You cannot set location for a non array/mapping/string type | |
function set(uint _num) public { | |
num = _num; | |
} | |
function setString(string memory _str) public { | |
str = _str; | |
} | |
// You can read from a state variable without sending a transaction. | |
function get() public view returns (uint) { | |
return num; | |
} | |
// You dont need to write a getter for public variables | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENSED | |
// SLIDES AVAILABLE | |
pragma solidity ^0.8.13; | |
contract Gas { | |
uint public i = 0; | |
// Using up all of the gas that you send causes your transaction to fail. | |
// State changes are undone. | |
// Gas spent are not refunded. | |
// WARNING: Reduce your gas limits before running this | |
function forever() public { | |
// Here we run a loop until all of the gas are spent | |
// and the transaction fails | |
while (true) { | |
i += 1; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENSED | |
pragma solidity ^0.8.13; | |
contract Function { | |
// Functions can return multiple values. | |
function returnMany() | |
public | |
pure | |
returns ( | |
uint, | |
bool, | |
uint | |
) | |
{ | |
return (1, true, 2); | |
} | |
// Return values can be named. | |
function named() | |
public | |
pure | |
returns ( | |
uint x, | |
bool b, | |
uint y | |
) | |
{ | |
return (1, true, 2); | |
} | |
// Return values can be assigned to their name. | |
// In this case the return statement can be omitted. | |
function assigned() | |
public | |
pure | |
returns ( | |
uint x, | |
bool b, | |
uint y | |
) | |
{ | |
x = 1; | |
b = true; | |
y = 2; | |
} | |
// Use destructuring assignment when calling another | |
// function that returns multiple values. | |
function destructuringAssignments() | |
public | |
pure | |
returns ( | |
uint, | |
bool, | |
uint, | |
uint, | |
uint | |
) | |
{ | |
(uint i, bool b, uint j) = returnMany(); | |
// Values can be left out. | |
(uint x, , uint y) = (4, 5, 6); | |
return (i, b, j, x, y); | |
} | |
// Cannot use map for either input or output | |
// Can use array for input | |
function arrayInput(uint[] memory _arr) public {} | |
// Can use array for output | |
uint[] public arr; | |
function arrayOutput() public view returns (uint[] memory) { | |
return arr; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENSED | |
pragma solidity ^0.8.13; | |
contract ViewAndPure { | |
uint public x = 1; | |
// Promise not to modify the state. | |
// https://docs.soliditylang.org/en/v0.8.14/contracts.html#view-functions | |
function addToX(uint y) public view returns (uint) { | |
return x + y; | |
} | |
// Promise not to modify or read from the state. | |
// https://docs.soliditylang.org/en/v0.8.14/contracts.html#pure-functions | |
function add(uint i, uint j) public pure returns (uint) { | |
return i + j; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENSED | |
pragma solidity ^0.8.13; | |
contract FunctionModifier { | |
// We will use these variables to demonstrate how to use | |
// modifiers. | |
address public owner; | |
uint public x = 10; | |
bool public locked; | |
constructor() { | |
// Set the transaction sender as the owner of the contract. | |
owner = msg.sender; | |
} | |
// Modifier to check that the caller is the owner of | |
// the contract. | |
modifier onlyOwner() { | |
require(msg.sender == owner, "Not owner"); | |
// Underscore is a special character only used inside | |
// a function modifier and it tells Solidity to | |
// execute the rest of the code. | |
_; | |
} | |
// Modifiers can take inputs. This modifier checks that the | |
// address passed in is not the zero address. | |
modifier validAddress(address _addr) { | |
require(_addr != address(0), "Not valid address"); | |
_; | |
} | |
function changeOwner(address _newOwner) public onlyOwner validAddress(_newOwner) { | |
owner = _newOwner; | |
} | |
// Modifiers can be called before and / or after a function. | |
// This modifier prevents a function from being called while | |
// it is still executing. | |
modifier noReentrancy() { | |
require(!locked, "No reentrancy"); | |
locked = true; | |
_; | |
locked = false; | |
} | |
function decrement(uint i) public noReentrancy { | |
x -= i; | |
if (i > 1) { | |
decrement(i - 1); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENSED | |
// SLIDES AVAILABLE | |
pragma solidity ^0.8.13; | |
// Base contract X | |
contract X { | |
string public name; | |
event LogX(string message); | |
constructor(string memory _name) { | |
name = _name; | |
emit LogX(_name); | |
} | |
} | |
// Base contract Y | |
contract Y { | |
string public text; | |
event LogY(string message); | |
constructor(string memory _text) { | |
text = _text; | |
emit LogY(_text); | |
} | |
} | |
// There are 2 ways to initialize parent contract with parameters. | |
// Pass the parameters here in the inheritance list. (Compile Time) | |
contract B is X("Input to X"), Y("Input to Y") { | |
} | |
contract C is X, Y { | |
// Pass the parameters here in the constructor, | |
// similar to function modifiers. (Publish Time) | |
constructor(string memory _name, string memory _text) X(_name) Y(_text) {} | |
} | |
// Inheritance graph must be linearizable | |
// So no M from C, | |
// COMMON GOTCHA!! | |
// Parent constructors are always called in the order of inheritance | |
// regardless of the order of parent contracts listed in the | |
// constructor of the child contract. | |
// Order of constructors called: | |
// 1. X | |
// 2. Y | |
// 3. D | |
contract D is X, Y { | |
constructor() X("X was called") Y("Y was called") {} | |
} | |
// Order of constructors called: | |
// 1. X | |
// 2. Y | |
// 3. E | |
contract E is X, Y { | |
constructor() Y("Y was called") X("X was called") {} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENSED | |
pragma solidity ^0.8.13; | |
contract Base { | |
// Private function can only be called | |
// - inside this contract | |
// Contracts that inherit this contract cannot call this function. | |
function privateFunc() private pure returns (string memory) { | |
return "private function called"; | |
} | |
function testPrivateFunc() public pure returns (string memory) { | |
return privateFunc(); | |
} | |
// Internal function can be called | |
// - inside this contract | |
// - inside contracts that inherit this contract | |
function internalFunc() internal pure returns (string memory) { | |
return "internal function called"; | |
} | |
function testInternalFunc() public pure virtual returns (string memory) { | |
return internalFunc(); | |
} | |
// Public functions can be called | |
// - inside this contract | |
// - inside contracts that inherit this contract | |
// - by other contracts and accounts | |
function publicFunc() public pure returns (string memory) { | |
return "public function called"; | |
} | |
// External functions can only be called | |
// - by other contracts and accounts | |
function externalFunc() external pure returns (string memory) { | |
return "external function called"; | |
} | |
// This function will not compile since we're trying to call | |
// an external function here. | |
// function testExternalFunc() public pure returns (string memory) { | |
// return externalFunc(); | |
// } | |
// State variables | |
string private privateVar = "my private variable"; | |
string internal internalVar = "my internal variable"; | |
string public publicVar = "my public variable"; | |
// State variables cannot be external so this code won't compile. | |
// string external externalVar = "my external variable"; | |
} | |
contract Child is Base { | |
// Inherited contracts do not have access to private functions | |
// and state variables. | |
// function testPrivateFunc() public pure returns (string memory) { | |
// return privateFunc(); | |
// } | |
// Internal function call be called inside child contracts. | |
function testInternalFunc() public pure override returns (string memory) { | |
return internalFunc(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENSED | |
pragma solidity ^0.8.13; | |
contract Event { | |
// Event declaration | |
// Up to 3 parameters can be indexed. | |
// Indexed parameters helps you filter the logs by the indexed parameter | |
event Log(address indexed sender, string message); | |
event AnotherLog(); | |
function test() public { | |
emit Log(msg.sender, "Hello World!"); | |
emit Log(msg.sender, "Hello EVM!"); | |
emit AnotherLog(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENSED | |
pragma solidity ^0.8.13; | |
contract Error { | |
function testRequire(uint _i) public pure { | |
// Require should be used to validate conditions such as: | |
// - inputs | |
// - conditions before execution | |
// - return values from calls to other functions | |
require(_i > 10, "Input must be greater than 10"); | |
} | |
function testRevert(uint _i) public pure { | |
// Revert is useful when the condition to check is complex. | |
// This code does the exact same thing as the example above | |
if (_i <= 10) { | |
revert("Input must be greater than 10"); | |
} | |
} | |
uint public num; | |
function testAssert() public view { | |
// Assert should only be used to test for internal errors, | |
// and to check invariants. | |
// Here we assert that num is always equal to 0 | |
// since it is impossible to update the value of num | |
// Assert burns all gas | |
assert(num == 0); | |
} | |
// custom error | |
error InsufficientBalance(uint balance, uint withdrawAmount); | |
function testCustomError(uint _withdrawAmount) public view { | |
uint bal = address(this).balance; | |
if (bal < _withdrawAmount) { | |
revert InsufficientBalance({balance: bal, withdrawAmount: _withdrawAmount}); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENSED | |
pragma solidity ^0.8.13; | |
contract Loop { | |
function loop() public { | |
// for loop | |
for (uint i = 0; i < 10; i++) { | |
if (i == 3) { | |
// Skip to next iteration with continue | |
continue; | |
} | |
if (i == 5) { | |
// Exit loop with break | |
break; | |
} | |
} | |
// while loop | |
uint j; | |
while (j < 10) { | |
j++; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENCED | |
pragma solidity ^0.8.13; | |
contract Array { | |
// Several ways to initialize an array | |
uint[] public arr; | |
uint[] public arr2 = [1, 2, 3]; | |
// Fixed sized array, all elements initialize to 0 | |
uint[10] public myFixedSizeArr; | |
function get(uint i) public view returns (uint) { | |
return arr[i]; | |
} | |
// Solidity can return the entire array. | |
// Do NOT Do this for non view functions | |
function getArr() public view returns (uint[] memory) { | |
return arr; | |
} | |
function push(uint i) public { | |
// Append to array | |
// This will increase the array length by 1. | |
arr.push(i); | |
} | |
function pop() public { | |
// Remove last element from array | |
// This will decrease the array length by 1 | |
arr.pop(); | |
} | |
function getLength() public view returns (uint) { | |
return arr.length; | |
} | |
function remove(uint index) public { | |
// Delete does not change the array length. | |
// It resets the value at index to it's default value, | |
// in this case 0 | |
delete arr[index]; | |
} | |
function examples() external { | |
// create array in memory, only fixed size can be created | |
uint[] memory a = new uint[](5); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENCED | |
pragma solidity ^0.8.13; | |
contract Mapping { | |
// Mapping from address to uint | |
mapping(address => uint) public myMap; | |
function get(address _addr) public view returns (uint) { | |
// Mapping always returns a value. | |
// If the value was never set, it will return the default value. | |
return myMap[_addr]; | |
} | |
function set(address _addr, uint _i) public { | |
// Update the value at this address | |
myMap[_addr] = _i; | |
} | |
function remove(address _addr) public { | |
// Reset the value to the default value. | |
delete myMap[_addr]; | |
} | |
} | |
contract NestedMapping { | |
// Nested mapping (mapping from address to another mapping) | |
mapping(address => mapping(uint => bool)) public nested; | |
function get(address _addr1, uint _i) public view returns (bool) { | |
// You can get values from a nested mapping | |
// even when it is not initialized | |
return nested[_addr1][_i]; | |
} | |
function set( | |
address _addr1, | |
uint _i, | |
bool _boo | |
) public { | |
nested[_addr1][_i] = _boo; | |
} | |
function remove(address _addr1, uint _i) public { | |
delete nested[_addr1][_i]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENCED | |
pragma solidity ^0.8.13; | |
contract Enum { | |
// Enum representing shipping status | |
enum Status { | |
Pending, | |
Shipped, | |
Accepted, | |
Rejected, | |
Canceled | |
} | |
// Default value is the first element listed in | |
// definition of the type, in this case "Pending" | |
Status public status; | |
// Returns uint | |
// Pending - 0 | |
// Shipped - 1 | |
// Accepted - 2 | |
// Rejected - 3 | |
// Canceled - 4 | |
function get() public view returns (Status) { | |
return status; | |
} | |
// Update status by passing uint into input | |
function set(Status _status) public { | |
status = _status; | |
} | |
// You can update to a specific enum like this | |
function cancel() public { | |
status = Status.Canceled; | |
} | |
// delete resets the enum to its first value, 0 | |
function reset() public { | |
delete status; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENCED | |
pragma solidity ^0.8.13; | |
contract Todos { | |
struct Todo { | |
string text; | |
bool completed; | |
} | |
// An array of 'Todo' structs | |
Todo[] public todos; | |
function create(string calldata _text) public { | |
// 3 ways to initialize a struct | |
// - calling it like a function | |
todos.push(Todo(_text, false)); | |
// key value mapping | |
todos.push(Todo({text: _text, completed: false})); | |
// initialize an empty struct and then update it | |
Todo memory todo; | |
todo.text = _text; | |
// todo.completed initialized to false | |
todos.push(todo); | |
} | |
// Solidity automatically created a getter for 'todos' so | |
// you don't actually need this function. | |
function get(uint _index) public view returns (string memory text, bool completed) { | |
Todo storage todo = todos[_index]; | |
return (todo.text, todo.completed); | |
} | |
// update text | |
function updateText(uint _index, string calldata _text) public { | |
Todo storage todo = todos[_index]; | |
todo.text = _text; | |
} | |
// update completed | |
function toggleCompleted(uint _index) public { | |
Todo storage todo = todos[_index]; | |
todo.completed = !todo.completed; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENCED | |
pragma solidity ^0.8.13; | |
contract Payable { | |
// Payable address can receive Ether | |
address payable public owner; | |
// Payable constructor can receive Ether | |
constructor() payable { | |
owner = payable(msg.sender); | |
} | |
// Function to deposit Ether into this contract. | |
// Call this function along with some Ether. | |
// The balance of this contract will be automatically updated. | |
function deposit() public payable {} | |
// Call this function along with some Ether. | |
// The function will throw an error since this function is not payable. | |
function notPayable() public {} | |
// Function to withdraw all Ether from this contract. | |
function withdraw() public { | |
// get the amount of Ether stored in this contract | |
uint amount = address(this).balance; | |
// send all Ether to owner | |
// Owner can receive Ether since the address of owner is payable | |
(bool success, ) = owner.call{value: amount}(""); | |
require(success, "Failed to send Ether"); | |
} | |
// Function to transfer Ether from this contract to address from input | |
function transfer(address payable _to, uint _amount) public { | |
// Note that "to" is declared as payable | |
(bool success, ) = _to.call{value: _amount}(""); | |
require(success, "Failed to send Ether"); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENCED | |
pragma solidity ^0.8.13; | |
contract ReceiveEther { | |
/* | |
Which function is called, fallback() or receive()? | |
send Ether | |
| | |
msg.data is empty? | |
/ \ | |
yes no | |
/ \ | |
receive() exists? fallback() | |
/ \ | |
yes no | |
/ \ | |
receive() fallback() | |
*/ | |
// Function to receive Ether. msg.data must be empty | |
receive() external payable {} | |
// Fallback function is called when msg.data is not empty | |
fallback() external payable {} | |
function getBalance() public view returns (uint) { | |
return address(this).balance; | |
} | |
} | |
contract SendEther { | |
function sendViaTransfer(address payable _to) public payable { | |
// This function is no longer recommended for sending Ether. | |
_to.transfer(msg.value); | |
} | |
function sendViaSend(address payable _to) public payable { | |
// Send returns a boolean value indicating success or failure. | |
// This function is not recommended for sending Ether. | |
bool sent = _to.send(msg.value); | |
require(sent, "Failed to send Ether"); | |
} | |
function sendViaCall(address payable _to) public payable { | |
// Call returns a boolean value indicating success or failure. | |
// This is the current recommended method to use. | |
(bool sent, bytes memory data) = _to.call{value: msg.value}(""); | |
require(sent, "Failed to send Ether"); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.13; | |
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.0.0/contracts/token/ERC20/ERC20.sol"; | |
contract AmithsToken is ERC20 { | |
constructor(string memory name, string memory symbol) ERC20(name, symbol) { | |
// Mint 100 tokens to msg.sender | |
// Similar to how | |
// 1 Rupee = 100 paise | |
// 1 token = 1 * (10 ** decimals) | |
_mint(msg.sender, 100 * 10**uint(decimals())); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment