diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e43b0f9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.DS_Store
diff --git a/README.md b/README.md
index b6d2408..f1d130d 100644
--- a/README.md
+++ b/README.md
@@ -1,30 +1,36 @@
-## š„·š»šµāļø playing pvp in the metaweb: solidity edition
-
+## š„·š»šµāļø web3 starting kit - solidity edition
-#### š start with [solidity tl; dr](solidity_tldr.md)
-
-
-
-
-#### š§° dirs in this repo
+* **start with [solidity tl; dr](basic_knowledge)**
+* **[your workspace](basic_knowledge/workspace)**
+* **[boilerplates](basic_knowledge/boilerplates)**
+* **[tokens standard](basic_knowledge/token_standards)**
+* **[bitwise](basic_knowledge/bitwise.md)**
+* **[applications contracts](advanced_knowledge/applications_contracts)**
+* **[merkle_trees](advanced_knowledge/merkle_trees)**
+* **[saving gas](advanced_knowledge/saving_gas)**
+* **[calldata](advanced_knowledge/calldata)**
+* **[events](advanced_knowledge/events)**
+* **[proxies](advanced_knowledge/proxies)**
+* **[wallets](advanced_knowledge/wallets)**
-* [set your workspace](workspace)
-* [tokens standard](token_standards)
-* [boilerplates](boilerplates)
-* [saving gas](saving_gas)
-* [abi encoding](abi_encoding)
-* [calldata](calldata)
-* [foundry](foundry)
-* [events](events)
-
-
+---
+### related autistic symposium's resources
+
+* **[ethernaut solutions and writeups in foundry](https://github.com/autistic-symposium/ethernaut-systematic-solutions-foundry-sol)**
+* **[blockchain auditing](https://github.com/autistic-symposium/blockchains-security-toolkit)**
+* **[amm-arb-toolkit-py](https://github.com/autistic-symposium/amm-arb-toolkit-py)**
+* **[mev-toolkit](https://github.com/autistic-symposium/mev-toolkit)**
+* **[searcher-cowswap-py](https://github.com/autistic-symposium/searcher-cowswap-py)**
+* **[generative storytelling](https://github.com/autistic-symposium/generative-sol)**
+
+
---
@@ -33,34 +39,29 @@
-##### learning solidity
+###### learning solidity
-* [solidity docs](https://docs.soliditylang.org/en/v0.8.12/)
-* [openzeppelin docs](https://docs.openzeppelin.com/)
-* [solidity by example](https://solidity-by-example.org/)
-* [smart contract programmer](https://www.youtube.com/channel/UCJWh7F3AFyQ_x01VKzr9eyA)
-* [solidity vscode plugin](https://marketplace.visualstudio.com/items?itemName=tintinweb.solidity-visual-auditor)
-* [learn solidity with examples, by jsagalli](https://github.com/James-Sangalli/learn-solidity-with-examples)
+* **[solidity docs](https://docs.soliditylang.org/en/v0.8.12/)**
+* **[openzeppelin docs](https://docs.openzeppelin.com/)**
+* **[solidity by example](https://solidity-by-example.org/)**
+* **[smart contract programmer](https://www.youtube.com/channel/UCJWh7F3AFyQ_x01VKzr9eyA)**
+* **[learn solidity with examples, by jsagalli](https://github.com/James-Sangalli/learn-solidity-with-examples)**
+* **[school of solana, by ackee](https://ackeeblockchain.com/school-of-solana)**
+
+###### writing beautiful code
+
+* **[solmate](https://github.com/transmissions11/solmate/)**
+* **[dapp.tools](https://dapp.tools/)**
+* **[solidity cheatsheet and best practices](https://github.com/manojpramesh/solidity-cheatsheet)**
-
+###### tools
-##### writing beautiful code
-
-* [solmate](https://github.com/transmissions11/solmate/)
-* [dapp.tools](https://dapp.tools/)
-* [solidity cheatsheet and best practices](https://github.com/manojpramesh/solidity-cheatsheet)
+* **[solidity vscode plugin](https://marketplace.visualstudio.com/items?itemName=tintinweb.solidity-visual-auditor)**
+* **[another solidity vscode plugin](https://marketplace.visualstudio.com/items?itemName=JuanBlanco.solidity)**
+###### advanced readings
-
-
-##### tools
-
-* [another solidity vscode plugin](https://marketplace.visualstudio.com/items?itemName=JuanBlanco.solidity)
-
-
-
-##### advanced readings
-
-* [reusable properties for ethereum contracts, by trailofbits](https://blog.trailofbits.com/2023/02/27/reusable-properties-ethereum-contracts-echidna/)
+* **[on some of my favorite openzeppelin smart contracts](https://mirror.xyz/go-outside.eth/7Q5DK8cZNZ5CP6ThJjEithPvjgckA24D2wb-j0Ps5-I)**
+* **[reusable properties for ethereum contracts, by trailofbits](https://blog.trailofbits.com/2023/02/27/reusable-properties-ethereum-contracts-echidna/)**
diff --git a/abi_encoding/README.md b/abi_encoding/README.md
deleted file mode 100644
index 1c77ab2..0000000
--- a/abi_encoding/README.md
+++ /dev/null
@@ -1,39 +0,0 @@
-## ABI encoding
-
-
-
-### tl; dr
-
-
-
-
-* the solidity built-in function `abi.encode` encodes solidity types into raw bytes, that can be interpreted directly by the EVM.
-
-
-```
-contract StringEncoding {
- bytes public encodedString = abi.encode("hacking");
-}
-```
-
-* this is what happens:
- 1. 1st (32 bytes) word = offset ā indicates at which bytes index the string starts. If you count 32 from the beginning (= index 32), you will reach the starting point of where the actual encoded string starts.
- 2. 2nd (32 bytes) word = string length ā in the case of the string, this indicates how many characters (including whitespaces) are included in the string.
- 3. 3rd (32 bytes) word = the actual utf8 encoded string ā each individual bytes corresponds to hex notation of a letter / character encoded in utf8.
-
-
-
-
-* other ABI Encodings
- * address payable -> address
- * contract -> address
- * enum -> uint8
- * struct -> tuple of elementry types
-
-
-
----
-
-### resources
-
-
diff --git a/advanced_knowledge/applications_contracts/README.md b/advanced_knowledge/applications_contracts/README.md
new file mode 100644
index 0000000..4633808
--- /dev/null
+++ b/advanced_knowledge/applications_contracts/README.md
@@ -0,0 +1,5 @@
+## a place to dump application contracts
+
+
+
+* disclaimer: these boilerplates might not be my code, but rather well-known references.
diff --git a/advanced_knowledge/applications_contracts/crowd_fund.sol b/advanced_knowledge/applications_contracts/crowd_fund.sol
new file mode 100644
index 0000000..73ac7b1
--- /dev/null
+++ b/advanced_knowledge/applications_contracts/crowd_fund.sol
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.17;
+
+/*
+Crowd fund ERC20 token
+
+User creates a campaign.
+Users can pledge, transferring their token to a campaign.
+After the campaign ends, campaign creator can claim the funds if total amount pledged is more than the campaign goal.
+Otherwise, campaign did not reach it's goal, users can withdraw their pledge.
+*/
+
+
+interface IERC20 {
+ function transfer(address, uint) external returns (bool);
+
+ function transferFrom(address, address, uint) external returns (bool);
+}
+
+contract CrowdFund {
+ event Launch(
+ uint id,
+ address indexed creator,
+ uint goal,
+ uint32 startAt,
+ uint32 endAt
+ );
+ event Cancel(uint id);
+ event Pledge(uint indexed id, address indexed caller, uint amount);
+ event Unpledge(uint indexed id, address indexed caller, uint amount);
+ event Claim(uint id);
+ event Refund(uint id, address indexed caller, uint amount);
+
+ struct Campaign {
+ // Creator of campaign
+ address creator;
+ // Amount of tokens to raise
+ uint goal;
+ // Total amount pledged
+ uint pledged;
+ // Timestamp of start of campaign
+ uint32 startAt;
+ // Timestamp of end of campaign
+ uint32 endAt;
+ // True if goal was reached and creator has claimed the tokens.
+ bool claimed;
+ }
+
+ IERC20 public immutable token;
+ // Total count of campaigns created.
+ // It is also used to generate id for new campaigns.
+ uint public count;
+ // Mapping from id to Campaign
+ mapping(uint => Campaign) public campaigns;
+ // Mapping from campaign id => pledger => amount pledged
+ mapping(uint => mapping(address => uint)) public pledgedAmount;
+
+ constructor(address _token) {
+ token = IERC20(_token);
+ }
+
+ function launch(uint _goal, uint32 _startAt, uint32 _endAt) external {
+ require(_startAt >= block.timestamp, "start at < now");
+ require(_endAt >= _startAt, "end at < start at");
+ require(_endAt <= block.timestamp + 90 days, "end at > max duration");
+
+ count += 1;
+ campaigns[count] = Campaign({
+ creator: msg.sender,
+ goal: _goal,
+ pledged: 0,
+ startAt: _startAt,
+ endAt: _endAt,
+ claimed: false
+ });
+
+ emit Launch(count, msg.sender, _goal, _startAt, _endAt);
+ }
+
+ function cancel(uint _id) external {
+ Campaign memory campaign = campaigns[_id];
+ require(campaign.creator == msg.sender, "not creator");
+ require(block.timestamp < campaign.startAt, "started");
+
+ delete campaigns[_id];
+ emit Cancel(_id);
+ }
+
+ function pledge(uint _id, uint _amount) external {
+ Campaign storage campaign = campaigns[_id];
+ require(block.timestamp >= campaign.startAt, "not started");
+ require(block.timestamp <= campaign.endAt, "ended");
+
+ campaign.pledged += _amount;
+ pledgedAmount[_id][msg.sender] += _amount;
+ token.transferFrom(msg.sender, address(this), _amount);
+
+ emit Pledge(_id, msg.sender, _amount);
+ }
+
+ function unpledge(uint _id, uint _amount) external {
+ Campaign storage campaign = campaigns[_id];
+ require(block.timestamp <= campaign.endAt, "ended");
+
+ campaign.pledged -= _amount;
+ pledgedAmount[_id][msg.sender] -= _amount;
+ token.transfer(msg.sender, _amount);
+
+ emit Unpledge(_id, msg.sender, _amount);
+ }
+
+ function claim(uint _id) external {
+ Campaign storage campaign = campaigns[_id];
+ require(campaign.creator == msg.sender, "not creator");
+ require(block.timestamp > campaign.endAt, "not ended");
+ require(campaign.pledged >= campaign.goal, "pledged < goal");
+ require(!campaign.claimed, "claimed");
+
+ campaign.claimed = true;
+ token.transfer(campaign.creator, campaign.pledged);
+
+ emit Claim(_id);
+ }
+
+ function refund(uint _id) external {
+ Campaign memory campaign = campaigns[_id];
+ require(block.timestamp > campaign.endAt, "not ended");
+ require(campaign.pledged < campaign.goal, "pledged >= goal");
+
+ uint bal = pledgedAmount[_id][msg.sender];
+ pledgedAmount[_id][msg.sender] = 0;
+ token.transfer(msg.sender, bal);
+
+ emit Refund(_id, msg.sender, bal);
+ }
+}
diff --git a/advanced_knowledge/applications_contracts/dutch_auction.sol b/advanced_knowledge/applications_contracts/dutch_auction.sol
new file mode 100644
index 0000000..787eaa4
--- /dev/null
+++ b/advanced_knowledge/applications_contracts/dutch_auction.sol
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.17;
+
+/*
+Dutch auction for NFT.
+
+Auction
+Seller of NFT deploys this contract setting a starting price for the NFT.
+Auction lasts for 7 days.
+Price of NFT decreases over time.
+Participants can buy by depositing ETH greater than the current price computed by the smart contract.
+Auction ends when a buyer buys the NFT.
+*/
+
+interface IERC721 {
+ function transferFrom(address _from, address _to, uint _nftId) external;
+}
+
+contract DutchAuction {
+ uint private constant DURATION = 7 days;
+
+ IERC721 public immutable nft;
+ uint public immutable nftId;
+
+ address payable public immutable seller;
+ uint public immutable startingPrice;
+ uint public immutable startAt;
+ uint public immutable expiresAt;
+ uint public immutable discountRate;
+
+ constructor(uint _startingPrice, uint _discountRate, address _nft, uint _nftId) {
+ seller = payable(msg.sender);
+ startingPrice = _startingPrice;
+ startAt = block.timestamp;
+ expiresAt = block.timestamp + DURATION;
+ discountRate = _discountRate;
+
+ require(_startingPrice >= _discountRate * DURATION, "starting price < min");
+
+ nft = IERC721(_nft);
+ nftId = _nftId;
+ }
+
+ function getPrice() public view returns (uint) {
+ uint timeElapsed = block.timestamp - startAt;
+ uint discount = discountRate * timeElapsed;
+ return startingPrice - discount;
+ }
+
+ function buy() external payable {
+ require(block.timestamp < expiresAt, "auction expired");
+
+ uint price = getPrice();
+ require(msg.value >= price, "ETH < price");
+
+ nft.transferFrom(seller, msg.sender, nftId);
+ uint refund = msg.value - price;
+ if (refund > 0) {
+ payable(msg.sender).transfer(refund);
+ }
+ selfdestruct(seller);
+ }
+}
diff --git a/advanced_knowledge/applications_contracts/english_auction.sol b/advanced_knowledge/applications_contracts/english_auction.sol
new file mode 100644
index 0000000..7ef501a
--- /dev/null
+++ b/advanced_knowledge/applications_contracts/english_auction.sol
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.17
+
+/*
+English auction for NFT.
+
+Auction
+Seller of NFT deploys this contract.
+Auction lasts for 7 days.
+Participants can bid by depositing ETH greater than the current highest bidder.
+All bidders can withdraw their bid if it is not the current highest bid.
+After the auction
+Highest bidder becomes the new owner of NFT.
+The seller receives the highest bid of ETH.
+*/
+
+
+
+
+interface IERC721 {
+ function safeTransferFrom(address from, address to, uint tokenId) external;
+
+ function transferFrom(address, address, uint) external;
+}
+
+contract EnglishAuction {
+ event Start();
+ event Bid(address indexed sender, uint amount);
+ event Withdraw(address indexed bidder, uint amount);
+ event End(address winner, uint amount);
+
+ IERC721 public nft;
+ uint public nftId;
+
+ address payable public seller;
+ uint public endAt;
+ bool public started;
+ bool public ended;
+
+ address public highestBidder;
+ uint public highestBid;
+ mapping(address => uint) public bids;
+
+ constructor(address _nft, uint _nftId, uint _startingBid) {
+ nft = IERC721(_nft);
+ nftId = _nftId;
+
+ seller = payable(msg.sender);
+ highestBid = _startingBid;
+ }
+
+ function start() external {
+ require(!started, "started");
+ require(msg.sender == seller, "not seller");
+
+ nft.transferFrom(msg.sender, address(this), nftId);
+ started = true;
+ endAt = block.timestamp + 7 days;
+
+ emit Start();
+ }
+
+ function bid() external payable {
+ require(started, "not started");
+ require(block.timestamp < endAt, "ended");
+ require(msg.value > highestBid, "value < highest");
+
+ if (highestBidder != address(0)) {
+ bids[highestBidder] += highestBid;
+ }
+
+ highestBidder = msg.sender;
+ highestBid = msg.value;
+
+ emit Bid(msg.sender, msg.value);
+ }
+
+ function withdraw() external {
+ uint bal = bids[msg.sender];
+ bids[msg.sender] = 0;
+ payable(msg.sender).transfer(bal);
+
+ emit Withdraw(msg.sender, bal);
+ }
+
+ function end() external {
+ require(started, "not started");
+ require(block.timestamp >= endAt, "not ended");
+ require(!ended, "ended");
+
+ ended = true;
+ if (highestBidder != address(0)) {
+ nft.safeTransferFrom(address(this), highestBidder, nftId);
+ seller.transfer(highestBid);
+ } else {
+ nft.safeTransferFrom(address(this), seller, nftId);
+ }
+
+ emit End(highestBidder, highestBid);
+ }
+}
diff --git a/advanced_knowledge/applications_contracts/multi_delegatecall.sol b/advanced_knowledge/applications_contracts/multi_delegatecall.sol
new file mode 100644
index 0000000..326aefd
--- /dev/null
+++ b/advanced_knowledge/applications_contracts/multi_delegatecall.sol
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.17;
+
+// An example of calling multiple functions with a single transaction, using delegatecall.
+
+contract MultiDelegatecall {
+ error DelegatecallFailed();
+
+ function multiDelegatecall(
+ bytes[] memory data
+ ) external payable returns (bytes[] memory results) {
+ results = new bytes[](data.length);
+
+ for (uint i; i < data.length; i++) {
+ (bool ok, bytes memory res) = address(this).delegatecall(data[i]);
+ if (!ok) {
+ revert DelegatecallFailed();
+ }
+ results[i] = res;
+ }
+ }
+}
+
+// Why use multi delegatecall? Why not multi call?
+// alice -> multi call --- call ---> test (msg.sender = multi call)
+// alice -> test --- delegatecall ---> test (msg.sender = alice)
+contract TestMultiDelegatecall is MultiDelegatecall {
+ event Log(address caller, string func, uint i);
+
+ function func1(uint x, uint y) external {
+ // msg.sender = alice
+ emit Log(msg.sender, "func1", x + y);
+ }
+
+ function func2() external returns (uint) {
+ // msg.sender = alice
+ emit Log(msg.sender, "func2", 2);
+ return 111;
+ }
+
+ mapping(address => uint) public balanceOf;
+
+ // WARNING: unsafe code when used in combination with multi-delegatecall
+ // user can mint multiple times for the price of msg.value
+ function mint() external payable {
+ balanceOf[msg.sender] += msg.value;
+ }
+}
+
+contract Helper {
+ function getFunc1Data(uint x, uint y) external pure returns (bytes memory) {
+ return abi.encodeWithSelector(TestMultiDelegatecall.func1.selector, x, y);
+ }
+
+ function getFunc2Data() external pure returns (bytes memory) {
+ return abi.encodeWithSelector(TestMultiDelegatecall.func2.selector);
+ }
+
+ function getMintData() external pure returns (bytes memory) {
+ return abi.encodeWithSelector(TestMultiDelegatecall.mint.selector);
+ }
+}
diff --git a/calldata/README.md b/advanced_knowledge/calldata/README.md
similarity index 57%
rename from calldata/README.md
rename to advanced_knowledge/calldata/README.md
index 9cc7113..6f62c2f 100644
--- a/calldata/README.md
+++ b/advanced_knowledge/calldata/README.md
@@ -2,10 +2,6 @@
-### tl; dr
-
-
-
* calldata is the encoded parameter(s) sent on functions by smart contracts to the evm (for example, through `abi.econde()`,`abi.econcdeWithSelector() for a particular interfaced function, or `abi.encodePacked()` for efficient dynamic variables).
* **function signature**: `selector()` generates the 4-bytes representing the method in the interface: this is how the evm knows which function is being interacted. function signatures are defined as the first four bytes of the Keccak hash of the canonical representation of the function signature.
@@ -16,7 +12,7 @@
- static variables: the encoded representation of `uint`, `address`, `bool`, `bytes`, `tuples`
- dynamics variables: non-fixed-size types: `bytes`, `string`, dynamic and fixed arrays `[]`
-* opcodes are 1 byte in length, leading to 256 different possible opcodes. the EVM only uses 140 opcodes.
+* opcodes are `1 byte` in length, leading to `256` different possible opcodes. the EVM only uses `140` opcodes.
@@ -26,10 +22,10 @@
-* [dedaub](https://library.dedaub.com/)
-* [ethervm.io](https://ethervm.io/decompile)
-* [panoramix](https://github.com/eveem-org/panoramix)
-* [froundry's cast with --debug](https://book.getfoundry.sh/cast/index.html)
+* **[dedaub](https://library.dedaub.com/)**
+* **[ethervm.io](https://ethervm.io/decompile)**
+* **[panoramix](https://github.com/eveem-org/panoramix)**
+* **[froundry's cast with --debug](https://book.getfoundry.sh/cast/index.html)**
@@ -41,5 +37,6 @@
-* [mev memoirs in the arena part 1, by noxx](https://noxx.substack.com/p/mev-memoirs-into-the-arena-chapter?s=r)
-* [mev memoirs in the arena part 2, by noxx](https://noxx.substack.com/p/mev-memoirs-into-the-arena-chapter-3e9)
+* **[mev memoirs in the arena part 1, by noxx](https://noxx.substack.com/p/mev-memoirs-into-the-arena-chapter?s=r)**
+* **[mev memoirs in the arena part 2, by noxx](https://noxx.substack.com/p/mev-memoirs-into-the-arena-chapter-3e9)**
+* **[ethereum tx enconding and legacy encoding](https://hoangtrinhj.com/articles/ethereum-transaction-encoding)**
diff --git a/advanced_knowledge/calldata/precompute_contract_address.sol b/advanced_knowledge/calldata/precompute_contract_address.sol
new file mode 100644
index 0000000..643fb3d
--- /dev/null
+++ b/advanced_knowledge/calldata/precompute_contract_address.sol
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.17;
+
+// Contract address can be precomputed, before the contract is deployed, using create2
+
+contract Factory {
+ // Returns the address of the newly deployed contract
+ function deploy(
+ address _owner,
+ uint _foo,
+ bytes32 _salt
+ ) public payable returns (address) {
+ // This syntax is a newer way to invoke create2 without assembly, you just need to pass salt
+ // https://docs.soliditylang.org/en/latest/control-structures.html#salted-contract-creations-create2
+ return address(new TestContract{salt: _salt}(_owner, _foo));
+ }
+}
+
+// This is the older way of doing it using assembly
+contract FactoryAssembly {
+ event Deployed(address addr, uint salt);
+
+ // 1. Get bytecode of contract to be deployed
+ // NOTE: _owner and _foo are arguments of the TestContract's constructor
+ function getBytecode(address _owner, uint _foo) public pure returns (bytes memory) {
+ bytes memory bytecode = type(TestContract).creationCode;
+
+ return abi.encodePacked(bytecode, abi.encode(_owner, _foo));
+ }
+
+ // 2. Compute the address of the contract to be deployed
+ // NOTE: _salt is a random number used to create an address
+ function getAddress(
+ bytes memory bytecode,
+ uint _salt
+ ) public view returns (address) {
+ bytes32 hash = keccak256(
+ abi.encodePacked(bytes1(0xff), address(this), _salt, keccak256(bytecode))
+ );
+
+ // NOTE: cast last 20 bytes of hash to address
+ return address(uint160(uint(hash)));
+ }
+
+ // 3. Deploy the contract
+ // NOTE:
+ // Check the event log Deployed which contains the address of the deployed TestContract.
+ // The address in the log should equal the address computed from above.
+ function deploy(bytes memory bytecode, uint _salt) public payable {
+ address addr;
+
+ /*
+ NOTE: How to call create2
+
+ create2(v, p, n, s)
+ create new contract with code at memory p to p + n
+ and send v wei
+ and return the new address
+ where new address = first 20 bytes of keccak256(0xff + address(this) + s + keccak256(mem[pā¦(p+n)))
+ s = big-endian 256-bit value
+ */
+ assembly {
+ addr := create2(
+ callvalue(), // wei sent with current call
+ // Actual code starts after skipping the first 32 bytes
+ add(bytecode, 0x20),
+ mload(bytecode), // Load the size of code contained in the first 32 bytes
+ _salt // Salt from function arguments
+ )
+
+ if iszero(extcodesize(addr)) {
+ revert(0, 0)
+ }
+ }
+
+ emit Deployed(addr, _salt);
+ }
+}
+
+contract TestContract {
+ address public owner;
+ uint public foo;
+
+ constructor(address _owner, uint _foo) payable {
+ owner = _owner;
+ foo = _foo;
+ }
+
+ function getBalance() public view returns (uint) {
+ return address(this).balance;
+ }
+}
diff --git a/events/README.md b/advanced_knowledge/events/README.md
similarity index 57%
rename from events/README.md
rename to advanced_knowledge/events/README.md
index d5debb8..ca08439 100644
--- a/events/README.md
+++ b/advanced_knowledge/events/README.md
@@ -1,6 +1,6 @@
-## events and topics
+## events, tx, topics
-### tl; dr
+
* solidity provides two types of events:
- anonymous: 4 topics may be indexed, and there is not signature hash (no filter)
@@ -8,6 +8,15 @@
+
---
-### resources
\ No newline at end of file
+### ethereum transactions
+
+
+
+
+
+
+
+
diff --git a/advanced_knowledge/merkle_trees/README.md b/advanced_knowledge/merkle_trees/README.md
new file mode 100644
index 0000000..2d88f2e
--- /dev/null
+++ b/advanced_knowledge/merkle_trees/README.md
@@ -0,0 +1,5 @@
+## a place to dump merkle trees examples
+
+
+
+* disclaimer: these boilerplates might not be my code, but rather well-known references.
diff --git a/advanced_knowledge/merkle_trees/tree_example1.sol b/advanced_knowledge/merkle_trees/tree_example1.sol
new file mode 100644
index 0000000..9b9d2c9
--- /dev/null
+++ b/advanced_knowledge/merkle_trees/tree_example1.sol
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.17;
+
+// Merkle tree allows you to cryptographically prove that an element is contained
+// in a set without revealing the entire set.
+
+contract MerkleProof {
+ function verify(
+ bytes32[] memory proof,
+ bytes32 root,
+ bytes32 leaf,
+ uint index
+ ) public pure returns (bool) {
+ bytes32 hash = leaf;
+
+ for (uint i = 0; i < proof.length; i++) {
+ bytes32 proofElement = proof[i];
+
+ if (index % 2 == 0) {
+ hash = keccak256(abi.encodePacked(hash, proofElement));
+ } else {
+ hash = keccak256(abi.encodePacked(proofElement, hash));
+ }
+
+ index = index / 2;
+ }
+
+ return hash == root;
+ }
+}
+
+contract TestMerkleProof is MerkleProof {
+ bytes32[] public hashes;
+
+ constructor() {
+ string[4] memory transactions = [
+ "alice -> bob",
+ "bob -> dave",
+ "carol -> alice",
+ "dave -> bob"
+ ];
+
+ for (uint i = 0; i < transactions.length; i++) {
+ hashes.push(keccak256(abi.encodePacked(transactions[i])));
+ }
+
+ uint n = transactions.length;
+ uint offset = 0;
+
+ while (n > 0) {
+ for (uint i = 0; i < n - 1; i += 2) {
+ hashes.push(
+ keccak256(
+ abi.encodePacked(hashes[offset + i], hashes[offset + i + 1])
+ )
+ );
+ }
+ offset += n;
+ n = n / 2;
+ }
+ }
+
+ function getRoot() public view returns (bytes32) {
+ return hashes[hashes.length - 1];
+ }
+
+ /* verify
+ 3rd leaf
+ 0xdca3326ad7e8121bf9cf9c12333e6b2271abe823ec9edfe42f813b1e768fa57b
+
+ root
+ 0xcc086fcc038189b4641db2cc4f1de3bb132aefbd65d510d817591550937818c7
+
+ index
+ 2
+
+ proof
+ 0x8da9e1c820f9dbd1589fd6585872bc1063588625729e7ab0797cfc63a00bd950
+ 0x995788ffc103b987ad50f5e5707fd094419eb12d9552cc423bd0cd86a3861433
+ */
+}
diff --git a/advanced_knowledge/proxies/README.md b/advanced_knowledge/proxies/README.md
new file mode 100644
index 0000000..d87d639
--- /dev/null
+++ b/advanced_knowledge/proxies/README.md
@@ -0,0 +1,5 @@
+## a place to dump proxy examples
+
+
+
+* disclaimer: these boilerplates might not be my code, but rather well-known references.
diff --git a/advanced_knowledge/proxies/deploy.sol b/advanced_knowledge/proxies/deploy.sol
new file mode 100644
index 0000000..bd30ace
--- /dev/null
+++ b/advanced_knowledge/proxies/deploy.sol
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.17;
+
+contract Proxy {
+ event Deploy(address);
+
+ receive() external payable {}
+
+ function deploy(bytes memory _code) external payable returns (address addr) {
+ assembly {
+ // create(v, p, n)
+ // v = amount of ETH to send
+ // p = pointer in memory to start of code
+ // n = size of code
+ addr := create(callvalue(), add(_code, 0x20), mload(_code))
+ }
+ // return address 0 on error
+ require(addr != address(0), "deploy failed");
+
+ emit Deploy(addr);
+ }
+
+ function execute(address _target, bytes memory _data) external payable {
+ (bool success, ) = _target.call{value: msg.value}(_data);
+ require(success, "failed");
+ }
+}
+
+contract TestContract1 {
+ address public owner = msg.sender;
+
+ function setOwner(address _owner) public {
+ require(msg.sender == owner, "not owner");
+ owner = _owner;
+ }
+}
+
+contract TestContract2 {
+ address public owner = msg.sender;
+ uint public value = msg.value;
+ uint public x;
+ uint public y;
+
+ constructor(uint _x, uint _y) payable {
+ x = _x;
+ y = _y;
+ }
+}
+
+contract Helper {
+ function getBytecode1() external pure returns (bytes memory) {
+ bytes memory bytecode = type(TestContract1).creationCode;
+ return bytecode;
+ }
+
+ function getBytecode2(uint _x, uint _y) external pure returns (bytes memory) {
+ bytes memory bytecode = type(TestContract2).creationCode;
+ return abi.encodePacked(bytecode, abi.encode(_x, _y));
+ }
+
+ function getCalldata(address _owner) external pure returns (bytes memory) {
+ return abi.encodeWithSignature("setOwner(address)", _owner);
+ }
+}
diff --git a/advanced_knowledge/proxies/minimum_proxy.sol b/advanced_knowledge/proxies/minimum_proxy.sol
new file mode 100644
index 0000000..30adf59
--- /dev/null
+++ b/advanced_knowledge/proxies/minimum_proxy.sol
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.17;
+
+
+
+contract MinimalProxy {
+ function clone(address target) external returns (address result) {
+ // convert address to 20 bytes
+ bytes20 targetBytes = bytes20(target);
+
+ // actual code //
+ // 3d602d80600a3d3981f3363d3d373d3d3d363d73bebebebebebebebebebebebebebebebebebebebe5af43d82803e903d91602b57fd5bf3
+
+ // creation code //
+ // copy runtime code into memory and return it
+ // 3d602d80600a3d3981f3
+
+ // runtime code //
+ // code to delegatecall to address
+ // 363d3d373d3d3d363d73 address 5af43d82803e903d91602b57fd5bf3
+
+ assembly {
+ /*
+ reads the 32 bytes of memory starting at pointer stored in 0x40
+
+ In solidity, the 0x40 slot in memory is special: it contains the "free memory pointer"
+ which points to the end of the currently allocated memory.
+ */
+ let clone := mload(0x40)
+ // store 32 bytes to memory starting at "clone"
+ mstore(
+ clone,
+ 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000
+ )
+
+ /*
+ | 20 bytes |
+ 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000
+ ^
+ pointer
+ */
+ // store 32 bytes to memory starting at "clone" + 20 bytes
+ // 0x14 = 20
+ mstore(add(clone, 0x14), targetBytes)
+
+ /*
+ | 20 bytes | 20 bytes |
+ 0x3d602d80600a3d3981f3363d3d373d3d3d363d73bebebebebebebebebebebebebebebebebebebebe
+ ^
+ pointer
+ */
+ // store 32 bytes to memory starting at "clone" + 40 bytes
+ // 0x28 = 40
+ mstore(
+ add(clone, 0x28),
+ 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
+ )
+
+ /*
+ | 20 bytes | 20 bytes | 15 bytes |
+ 0x3d602d80600a3d3981f3363d3d373d3d3d363d73bebebebebebebebebebebebebebebebebebebebe5af43d82803e903d91602b57fd5bf3
+ */
+ // create new contract
+ // send 0 Ether
+ // code starts at pointer stored in "clone"
+ // code size 0x37 (55 bytes)
+ result := create(0, clone, 0x37)
+ }
+ }
+}
diff --git a/advanced_knowledge/proxies/upgradeable_proxy.sol b/advanced_knowledge/proxies/upgradeable_proxy.sol
new file mode 100644
index 0000000..7135c15
--- /dev/null
+++ b/advanced_knowledge/proxies/upgradeable_proxy.sol
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.17;
+
+// Transparent upgradeable proxy pattern
+
+contract CounterV1 {
+ uint public count;
+
+ function inc() external {
+ count += 1;
+ }
+}
+
+contract CounterV2 {
+ uint public count;
+
+ function inc() external {
+ count += 1;
+ }
+
+ function dec() external {
+ count -= 1;
+ }
+}
+
+contract BuggyProxy {
+ address public implementation;
+ address public admin;
+
+ constructor() {
+ admin = msg.sender;
+ }
+
+ function _delegate() private {
+ (bool ok, ) = implementation.delegatecall(msg.data);
+ require(ok, "delegatecall failed");
+ }
+
+ fallback() external payable {
+ _delegate();
+ }
+
+ receive() external payable {
+ _delegate();
+ }
+
+ function upgradeTo(address _implementation) external {
+ require(msg.sender == admin, "not authorized");
+ implementation = _implementation;
+ }
+}
+
+contract Dev {
+ function selectors() external view returns (bytes4, bytes4, bytes4) {
+ return (
+ Proxy.admin.selector,
+ Proxy.implementation.selector,
+ Proxy.upgradeTo.selector
+ );
+ }
+}
+
+contract Proxy {
+ // All functions / variables should be private, forward all calls to fallback
+
+ // -1 for unknown preimage
+ // 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc
+ bytes32 private constant IMPLEMENTATION_SLOT =
+ bytes32(uint(keccak256("eip1967.proxy.implementation")) - 1);
+ // 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103
+ bytes32 private constant ADMIN_SLOT =
+ bytes32(uint(keccak256("eip1967.proxy.admin")) - 1);
+
+ constructor() {
+ _setAdmin(msg.sender);
+ }
+
+ modifier ifAdmin() {
+ if (msg.sender == _getAdmin()) {
+ _;
+ } else {
+ _fallback();
+ }
+ }
+
+ function _getAdmin() private view returns (address) {
+ return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
+ }
+
+ function _setAdmin(address _admin) private {
+ require(_admin != address(0), "admin = zero address");
+ StorageSlot.getAddressSlot(ADMIN_SLOT).value = _admin;
+ }
+
+ function _getImplementation() private view returns (address) {
+ return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
+ }
+
+ function _setImplementation(address _implementation) private {
+ require(_implementation.code.length > 0, "implementation is not contract");
+ StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = _implementation;
+ }
+
+ // Admin interface //
+ function changeAdmin(address _admin) external ifAdmin {
+ _setAdmin(_admin);
+ }
+
+ // 0x3659cfe6
+ function upgradeTo(address _implementation) external ifAdmin {
+ _setImplementation(_implementation);
+ }
+
+ // 0xf851a440
+ function admin() external ifAdmin returns (address) {
+ return _getAdmin();
+ }
+
+ // 0x5c60da1b
+ function implementation() external ifAdmin returns (address) {
+ return _getImplementation();
+ }
+
+ // User interface //
+ function _delegate(address _implementation) internal virtual {
+ assembly {
+ // Copy msg.data. We take full control of memory in this inline assembly
+ // block because it will not return to Solidity code. We overwrite the
+ // Solidity scratch pad at memory position 0.
+
+ // calldatacopy(t, f, s) - copy s bytes from calldata at position f to mem at position t
+ // calldatasize() - size of call data in bytes
+ calldatacopy(0, 0, calldatasize())
+
+ // Call the implementation.
+ // out and outsize are 0 because we don't know the size yet.
+
+ // delegatecall(g, a, in, insize, out, outsize) -
+ // - call contract at address a
+ // - with input mem[inā¦(in+insize))
+ // - providing g gas
+ // - and output area mem[outā¦(out+outsize))
+ // - returning 0 on error (eg. out of gas) and 1 on success
+ let result := delegatecall(gas(), _implementation, 0, calldatasize(), 0, 0)
+
+ // Copy the returned data.
+ // returndatacopy(t, f, s) - copy s bytes from returndata at position f to mem at position t
+ // returndatasize() - size of the last returndata
+ returndatacopy(0, 0, returndatasize())
+
+ switch result
+ // delegatecall returns 0 on error.
+ case 0 {
+ // revert(p, s) - end execution, revert state changes, return data mem[pā¦(p+s))
+ revert(0, returndatasize())
+ }
+ default {
+ // return(p, s) - end execution, return data mem[pā¦(p+s))
+ return(0, returndatasize())
+ }
+ }
+ }
+
+ function _fallback() private {
+ _delegate(_getImplementation());
+ }
+
+ fallback() external payable {
+ _fallback();
+ }
+
+ receive() external payable {
+ _fallback();
+ }
+}
+
+contract ProxyAdmin {
+ address public owner;
+
+ constructor() {
+ owner = msg.sender;
+ }
+
+ modifier onlyOwner() {
+ require(msg.sender == owner, "not owner");
+ _;
+ }
+
+ function getProxyAdmin(address proxy) external view returns (address) {
+ (bool ok, bytes memory res) = proxy.staticcall(abi.encodeCall(Proxy.admin, ()));
+ require(ok, "call failed");
+ return abi.decode(res, (address));
+ }
+
+ function getProxyImplementation(address proxy) external view returns (address) {
+ (bool ok, bytes memory res) = proxy.staticcall(
+ abi.encodeCall(Proxy.implementation, ())
+ );
+ require(ok, "call failed");
+ return abi.decode(res, (address));
+ }
+
+ function changeProxyAdmin(address payable proxy, address admin) external onlyOwner {
+ Proxy(proxy).changeAdmin(admin);
+ }
+
+ function upgrade(address payable proxy, address implementation) external onlyOwner {
+ Proxy(proxy).upgradeTo(implementation);
+ }
+}
+
+library StorageSlot {
+ struct AddressSlot {
+ address value;
+ }
+
+ function getAddressSlot(
+ bytes32 slot
+ ) internal pure returns (AddressSlot storage r) {
+ assembly {
+ r.slot := slot
+ }
+ }
+}
+
+contract TestSlot {
+ bytes32 public constant slot = keccak256("TEST_SLOT");
+
+ function getSlot() external view returns (address) {
+ return StorageSlot.getAddressSlot(slot).value;
+ }
+
+ function writeSlot(address _addr) external {
+ StorageSlot.getAddressSlot(slot).value = _addr;
+ }
+}
diff --git a/advanced_knowledge/saving_gas/README.md b/advanced_knowledge/saving_gas/README.md
new file mode 100644
index 0000000..ed15f12
--- /dev/null
+++ b/advanced_knowledge/saving_gas/README.md
@@ -0,0 +1,292 @@
+## gas optimization
+
+
+
+- gas is the cost for on-chain computation and storage. examples:
+ - addition costs `3` gas, `keccak-256` costs `30 gas + 6 gas` for each `256 bits` of data being hashed.
+ - sending a transaction costs `21,000 gas` (intrinsic gas).
+ - creating a contract costs `32000 gas`.
+- each **calldata** byte costs gas (gas per byte equal to `0`, and `16 gas` for the others), the larger the size of the transaction data, the higher the gas fees.
+- each opcode has a [specific fixed cost to be paid upon execution](https://www.evm.codes/?fork=arrowGlacier).
+- calculate gas for your code online at [remix](https://remix.ethereum.org/).
+
+
+
+
+----
+
+
+### general tricks to save gas
+
+
+
+* replace `memory` with `calldata`
+* load state variable to memory
+* replace for loop `i++` with `++i`
+* caching array elements
+* short circuits
+* brute force hashes of function names to find those that start `0000`, so this can save around `50 gas`.
+* if you donāt need a variable anymore, you should delete it using the delete keyword provided by solidity or by setting it to its default value.
+* avoid calls to other contracts.
+
+
+
+
+
+
+
+
+
+
+```
+// gas golf
+contract GasGolf {
+ // start - 50908 gas
+ // use calldata - 49163 gas
+ // load state variables to memory - 48952 gas
+ // short circuit - 48634 gas
+ // loop increments - 48244 gas
+ // cache array length - 48209 gas
+ // load array elements to memory - 48047 gas
+ // uncheck i overflow/underflow - 47309 gas
+
+ uint public total;
+
+ // start - not gas optimized
+ // function sumIfEvenAndLessThan99(uint[] memory nums) external {
+ // for (uint i = 0; i < nums.length; i += 1) {
+ // bool isEven = nums[i] % 2 == 0;
+ // bool isLessThan99 = nums[i] < 99;
+ // if (isEven && isLessThan99) {
+ // total += nums[i];
+ // }
+ // }
+ // }
+
+ // gas optimized
+ // [1, 2, 3, 4, 5, 100]
+ function sumIfEvenAndLessThan99(uint[] calldata nums) external {
+ uint _total = total;
+ uint len = nums.length;
+
+ for (uint i = 0; i < len; ) {
+ uint num = nums[i];
+ if (num % 2 == 0 && num < 99) {
+ _total += num;
+ }
+ unchecked {
+ ++i;
+ }
+ }
+
+ total = _total;
+ }
+}
+```
+
+
+
+
+---
+
+### pack variables
+
+
+
+* this code is an example of poorĀ code and will consume 3 storage slot:
+
+```
+uint8 numberOne;
+uint256 bigNumber;
+uint8 numberTwo;
+```
+
+
+
+* a much more efficient way to do this in solidity will be:
+
+```
+uint8 numberOne;
+uint8 numberTwo;
+uint256 bigNumber;
+```
+
+
+
+---
+
+
+### constant vs. immutable variables
+
+
+
+* constant values can sometimes be cheaper than immutable values:
+ - for a constant variable, the expression assigned to it is copied to all the places where it is accessed and also re-evaluated each time, allowing local optimizations.
+ - immutable variables are evaluated once at construction time and their value is copied to all the places in the code where they are accessed. For these values, 32 bytes are reserved, even if they would fit in fewer bytes.
+
+
+
+---
+
+### mappings are cheaper than arrays
+
+
+
+- avoid dynamically sized arrays
+- an array is not stored sequentially in memory but as a mapping.
+- you can pack Arrays but not Mappings.
+- itās cheaper to use arrays if you are using smaller elements like `uint8` which can be packed together.
+- you canāt get the length of a mapping or parse through all its elements, so depending on your use case, you might be forced to use an Array even though it might cost you more gas.
+
+
+
+---
+
+### use bytes32 rather than string/bytes
+
+
+
+- if you can fit your data in 32 bytes, then you should use `bytes32` datatype rather than bytes or strings as it is much cheaper in solidity.
+- any fixed size variable in solidity is cheaper than variable size.
+
+
+
+---
+
+### modifiers
+
+
+
+- for all the public functions, the input parameters are copied to memory automatically, and it costs gas.
+- if your function is only called externally, then you should explicitly mark it as external.
+- external functionās parameters are not copied into memory but are read from `calldata` directly.
+- internal and private are both cheaper than public and external when called from inside the contract in some cases.
+
+
+
+---
+
+### no need to initialize variables with default values
+
+
+
+- if a variable is not set/initialized, it is assumed to have the default value (0, false, 0x0 etc depending on the data type). If you explicitly initialize it with its default value, you are just wasting gas.
+
+```
+uint256 hello = 0; //bad, expensive
+uint256 world; //good, cheap
+```
+
+
+
+---
+
+### make use of single line swaps
+
+
+
+
+- this is space-efficient:
+
+```
+(hello, world) = (world, hello)
+```
+
+
+
+---
+
+### negative gas costs
+
+
+
+- deleting a contract (SELFDESTRUCT) is worth a refund of 24,000 gas.
+- changing a storage address from a nonzero value to zero (SSTORE[x] = 0) is worth a refund of 15,000 gas.
+
+
+
+---
+
+### [i ++](https://twitter.com/high_byte/status/1647080662094995457?s=20)
+
+
+
+* instead of i++ you should write the ++ above the i.
+
+```
+while (true)
+ uint256 i = 0;
+ ++
+ i
+ ;
+```
+
+
+
+----
+
+
+### unchecked math
+
+
+
+* overflow and underflow of numbers in solidity 0.8 throw an error. this can be disabled with `unchecked`.
+* disabling overflow / underflow check saves gas.
+
+
+
+```
+contract UncheckedMath {
+ function add(uint x, uint y) external pure returns (uint) {
+ // 22291 gas
+ // return x + y;
+
+ // 22103 gas
+ unchecked {
+ return x + y;
+ }
+ }
+
+ function sub(uint x, uint y) external pure returns (uint) {
+ // 22329 gas
+ // return x - y;
+
+ // 22147 gas
+ unchecked {
+ return x - y;
+ }
+ }
+
+ function sumOfCubes(uint x, uint y) external pure returns (uint) {
+ // Wrap complex math logic inside unchecked
+ unchecked {
+ uint x3 = x * x * x;
+ uint y3 = y * y * y;
+
+ return x3 + y3;
+ }
+ }
+}
+
+```
+
+
+
+
+
+---
+
+### resources
+
+
+
+* **[truffle contract size](https://github.com/IoBuilders/truffle-contract-size)**
+* **[foundry book on gas](https://book.getfoundry.sh/forge/gas-reports)**
+* **[solidity gas optimizations](https://mirror.xyz/haruxe.eth/DW5verFv8KsYOBC0SxqWORYry17kPdeS94JqOVkgxAA)**
+* **[hardhat on gas optimization](https://medium.com/@thelasthash/%EF%B8%8F-gas-optimization-with-hardhat-1e553eaea311)**
+* **[resources for gas optimization](https://github.com/kadenzipfel/gas-optimizations)**
+* **[awesome solidity gas optimization](https://github.com/iskdrews/awesome-solidity-gas-optimization)**
+* **[mev-toolkit resources](https://github.com/go-outside-labs/mev-toolkit/tree/main/MEV_searchers/code_resources/gas_optimization)**
+* **[how gas optimization can streamline smart contracts](https://medium.com/@ayomilk1/maximizing-efficiency-how-gas-optimization-can-streamline-your-smart-contracts-4bafcc6bf321)**
+* **[math, solidity & gas optimizations | part 1/3](https://officercia.mirror.xyz/vtVVxbV35ETiBGxm-IpcFPcsK2_ZkL7vgiiGUkeSsP0)**
+
diff --git a/advanced_knowledge/saving_gas/gasless_token_transfer.sol b/advanced_knowledge/saving_gas/gasless_token_transfer.sol
new file mode 100644
index 0000000..28587ba
--- /dev/null
+++ b/advanced_knowledge/saving_gas/gasless_token_transfer.sol
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.18;
+
+// gaslless erc20 token transfer with meta transaction
+
+interface IERC20Permit {
+ function totalSupply() external view returns (uint256);
+
+ function balanceOf(address account) external view returns (uint256);
+
+ function transfer(address recipient, uint256 amount) external returns (bool);
+
+ function allowance(address owner, address spender) external view returns (uint256);
+
+ function approve(address spender, uint256 amount) external returns (bool);
+
+ function transferFrom(
+ address sender,
+ address recipient,
+ uint256 amount
+ ) external returns (bool);
+
+ function permit(
+ address owner,
+ address spender,
+ uint256 value,
+ uint256 deadline,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) external;
+
+ event Transfer(address indexed from, address indexed to, uint256 value);
+ event Approval(address indexed owner, address indexed spender, uint256 value);
+}
+
+contract GaslessTokenTransfer {
+ function send(
+ address token,
+ address sender,
+ address receiver,
+ uint256 amount,
+ uint256 fee,
+ uint256 deadline,
+ // Permit signature
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) external {
+ // Permit
+ IERC20Permit(token).permit(
+ sender,
+ address(this),
+ amount + fee,
+ deadline,
+ v,
+ r,
+ s
+ );
+ // Send amount to receiver
+ IERC20Permit(token).transferFrom(sender, receiver, amount);
+ // Take fee - send fee to msg.sender
+ IERC20Permit(token).transferFrom(sender, msg.sender, fee);
+ }
+}
diff --git a/advanced_knowledge/wallets/README.md b/advanced_knowledge/wallets/README.md
new file mode 100644
index 0000000..5d74aae
--- /dev/null
+++ b/advanced_knowledge/wallets/README.md
@@ -0,0 +1,5 @@
+## a place to dump wallets examples
+
+
+
+* disclaimer: these boilerplates might not be my code, but rather well-known references.
diff --git a/advanced_knowledge/wallets/bidirectional_payment_channel.sol b/advanced_knowledge/wallets/bidirectional_payment_channel.sol
new file mode 100644
index 0000000..406b028
--- /dev/null
+++ b/advanced_knowledge/wallets/bidirectional_payment_channel.sol
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.17;
+
+/*
+
+Bi-directional payment channels allow participants Alice and Bob to repeatedly transfer Ether off chain.
+
+Payments can go both ways, Alice pays Bob and Bob pays Alice.
+
+Opening a channel
+1. Alice and Bob fund a multi-sig wallet
+2. Precompute payment channel address
+3. Alice and Bob exchanges signatures of initial balances
+4. Alice and Bob creates a transaction that can deploy a payment channel from
+ the multi-sig wallet
+
+Update channel balances
+1. Repeat steps 1 - 3 from opening a channel
+2. From multi-sig wallet create a transaction that will
+ - delete the transaction that would have deployed the old payment channel
+ - and then create a transaction that can deploy a payment channel with the
+ new balances
+
+Closing a channel when Alice and Bob agree on the final balance
+1. From multi-sig wallet create a transaction that will
+ - send payments to Alice and Bob
+ - and then delete the transaction that would have created the payment channel
+
+Closing a channel when Alice and Bob do not agree on the final balances
+1. Deploy payment channel from multi-sig
+2. call challengeExit() to start the process of closing a channel
+3. Alice and Bob can withdraw funds once the channel is expired
+*/
+
+import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.5/contracts/utils/cryptography/ECDSA.sol";
+
+contract BiDirectionalPaymentChannel {
+ using ECDSA for bytes32;
+
+ event ChallengeExit(address indexed sender, uint nonce);
+ event Withdraw(address indexed to, uint amount);
+
+ address payable[2] public users;
+ mapping(address => bool) public isUser;
+
+ mapping(address => uint) public balances;
+
+ uint public challengePeriod;
+ uint public expiresAt;
+ uint public nonce;
+
+ modifier checkBalances(uint[2] memory _balances) {
+ require(
+ address(this).balance >= _balances[0] + _balances[1],
+ "balance of contract must be >= to the total balance of users"
+ );
+ _;
+ }
+
+ // NOTE: deposit from multi-sig wallet
+ constructor(
+ address payable[2] memory _users,
+ uint[2] memory _balances,
+ uint _expiresAt,
+ uint _challengePeriod
+ ) payable checkBalances(_balances) {
+ require(_expiresAt > block.timestamp, "Expiration must be > now");
+ require(_challengePeriod > 0, "Challenge period must be > 0");
+
+ for (uint i = 0; i < _users.length; i++) {
+ address payable user = _users[i];
+
+ require(!isUser[user], "user must be unique");
+ users[i] = user;
+ isUser[user] = true;
+
+ balances[user] = _balances[i];
+ }
+
+ expiresAt = _expiresAt;
+ challengePeriod = _challengePeriod;
+ }
+
+ function verify(
+ bytes[2] memory _signatures,
+ address _contract,
+ address[2] memory _signers,
+ uint[2] memory _balances,
+ uint _nonce
+ ) public pure returns (bool) {
+ for (uint i = 0; i < _signatures.length; i++) {
+ /*
+ NOTE: sign with address of this contract to protect
+ agains replay attack on other contracts
+ */
+ bool valid = _signers[i] ==
+ keccak256(abi.encodePacked(_contract, _balances, _nonce))
+ .toEthSignedMessageHash()
+ .recover(_signatures[i]);
+
+ if (!valid) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ modifier checkSignatures(
+ bytes[2] memory _signatures,
+ uint[2] memory _balances,
+ uint _nonce
+ ) {
+ // Note: copy storage array to memory
+ address[2] memory signers;
+ for (uint i = 0; i < users.length; i++) {
+ signers[i] = users[i];
+ }
+
+ require(
+ verify(_signatures, address(this), signers, _balances, _nonce),
+ "Invalid signature"
+ );
+
+ _;
+ }
+
+ modifier onlyUser() {
+ require(isUser[msg.sender], "Not user");
+ _;
+ }
+
+ function challengeExit(
+ uint[2] memory _balances,
+ uint _nonce,
+ bytes[2] memory _signatures
+ )
+ public
+ onlyUser
+ checkSignatures(_signatures, _balances, _nonce)
+ checkBalances(_balances)
+ {
+ require(block.timestamp < expiresAt, "Expired challenge period");
+ require(_nonce > nonce, "Nonce must be greater than the current nonce");
+
+ for (uint i = 0; i < _balances.length; i++) {
+ balances[users[i]] = _balances[i];
+ }
+
+ nonce = _nonce;
+ expiresAt = block.timestamp + challengePeriod;
+
+ emit ChallengeExit(msg.sender, nonce);
+ }
+
+ function withdraw() public onlyUser {
+ require(block.timestamp >= expiresAt, "Challenge period has not expired yet");
+
+ uint amount = balances[msg.sender];
+ balances[msg.sender] = 0;
+
+ (bool sent, ) = msg.sender.call{value: amount}("");
+ require(sent, "Failed to send Ether");
+
+ emit Withdraw(msg.sender, amount);
+ }
+}
diff --git a/advanced_knowledge/wallets/multisig.sol b/advanced_knowledge/wallets/multisig.sol
new file mode 100644
index 0000000..9e39034
--- /dev/null
+++ b/advanced_knowledge/wallets/multisig.sol
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.17;
+
+// Let's create an multi-sig wallet. Here are the specifications.
+// The wallet owners can
+// - submit a transaction
+// - approve and revoke approval of pending transcations
+// - anyone can execute a transcation after enough owners has approved it.
+
+
+contract MultiSigWallet {
+ event Deposit(address indexed sender, uint amount, uint balance);
+ event SubmitTransaction(
+ address indexed owner,
+ uint indexed txIndex,
+ address indexed to,
+ uint value,
+ bytes data
+ );
+ event ConfirmTransaction(address indexed owner, uint indexed txIndex);
+ event RevokeConfirmation(address indexed owner, uint indexed txIndex);
+ event ExecuteTransaction(address indexed owner, uint indexed txIndex);
+
+ address[] public owners;
+ mapping(address => bool) public isOwner;
+ uint public numConfirmationsRequired;
+
+ struct Transaction {
+ address to;
+ uint value;
+ bytes data;
+ bool executed;
+ uint numConfirmations;
+ }
+
+ // mapping from tx index => owner => bool
+ mapping(uint => mapping(address => bool)) public isConfirmed;
+
+ Transaction[] public transactions;
+
+ modifier onlyOwner() {
+ require(isOwner[msg.sender], "not owner");
+ _;
+ }
+
+ modifier txExists(uint _txIndex) {
+ require(_txIndex < transactions.length, "tx does not exist");
+ _;
+ }
+
+ modifier notExecuted(uint _txIndex) {
+ require(!transactions[_txIndex].executed, "tx already executed");
+ _;
+ }
+
+ modifier notConfirmed(uint _txIndex) {
+ require(!isConfirmed[_txIndex][msg.sender], "tx already confirmed");
+ _;
+ }
+
+ constructor(address[] memory _owners, uint _numConfirmationsRequired) {
+ require(_owners.length > 0, "owners required");
+ require(
+ _numConfirmationsRequired > 0 &&
+ _numConfirmationsRequired <= _owners.length,
+ "invalid number of required confirmations"
+ );
+
+ for (uint i = 0; i < _owners.length; i++) {
+ address owner = _owners[i];
+
+ require(owner != address(0), "invalid owner");
+ require(!isOwner[owner], "owner not unique");
+
+ isOwner[owner] = true;
+ owners.push(owner);
+ }
+
+ numConfirmationsRequired = _numConfirmationsRequired;
+ }
+
+ receive() external payable {
+ emit Deposit(msg.sender, msg.value, address(this).balance);
+ }
+
+ function submitTransaction(
+ address _to,
+ uint _value,
+ bytes memory _data
+ ) public onlyOwner {
+ uint txIndex = transactions.length;
+
+ transactions.push(
+ Transaction({
+ to: _to,
+ value: _value,
+ data: _data,
+ executed: false,
+ numConfirmations: 0
+ })
+ );
+
+ emit SubmitTransaction(msg.sender, txIndex, _to, _value, _data);
+ }
+
+ function confirmTransaction(
+ uint _txIndex
+ ) public onlyOwner txExists(_txIndex) notExecuted(_txIndex) notConfirmed(_txIndex) {
+ Transaction storage transaction = transactions[_txIndex];
+ transaction.numConfirmations += 1;
+ isConfirmed[_txIndex][msg.sender] = true;
+
+ emit ConfirmTransaction(msg.sender, _txIndex);
+ }
+
+ function executeTransaction(
+ uint _txIndex
+ ) public onlyOwner txExists(_txIndex) notExecuted(_txIndex) {
+ Transaction storage transaction = transactions[_txIndex];
+
+ require(
+ transaction.numConfirmations >= numConfirmationsRequired,
+ "cannot execute tx"
+ );
+
+ transaction.executed = true;
+
+ (bool success, ) = transaction.to.call{value: transaction.value}(
+ transaction.data
+ );
+ require(success, "tx failed");
+
+ emit ExecuteTransaction(msg.sender, _txIndex);
+ }
+
+ function revokeConfirmation(
+ uint _txIndex
+ ) public onlyOwner txExists(_txIndex) notExecuted(_txIndex) {
+ Transaction storage transaction = transactions[_txIndex];
+
+ require(isConfirmed[_txIndex][msg.sender], "tx not confirmed");
+
+ transaction.numConfirmations -= 1;
+ isConfirmed[_txIndex][msg.sender] = false;
+
+ emit RevokeConfirmation(msg.sender, _txIndex);
+ }
+
+ function getOwners() public view returns (address[] memory) {
+ return owners;
+ }
+
+ function getTransactionCount() public view returns (uint) {
+ return transactions.length;
+ }
+
+ function getTransaction(
+ uint _txIndex
+ )
+ public
+ view
+ returns (
+ address to,
+ uint value,
+ bytes memory data,
+ bool executed,
+ uint numConfirmations
+ )
+ {
+ Transaction storage transaction = transactions[_txIndex];
+
+ return (
+ transaction.to,
+ transaction.value,
+ transaction.data,
+ transaction.executed,
+ transaction.numConfirmations
+ );
+ }
+}
diff --git a/advanced_knowledge/wallets/send_tx_multisig.sol b/advanced_knowledge/wallets/send_tx_multisig.sol
new file mode 100644
index 0000000..1727a07
--- /dev/null
+++ b/advanced_knowledge/wallets/send_tx_multisig.sol
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.17;
+
+contract TestContract {
+ uint public i;
+
+ function callMe(uint j) public {
+ i += j;
+ }
+
+ function getData() public pure returns (bytes memory) {
+ return abi.encodeWithSignature("callMe(uint256)", 123);
+ }
+}
diff --git a/advanced_knowledge/wallets/unidirectional_payment_channel.sol b/advanced_knowledge/wallets/unidirectional_payment_channel.sol
new file mode 100644
index 0000000..ce9c160
--- /dev/null
+++ b/advanced_knowledge/wallets/unidirectional_payment_channel.sol
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.17;
+
+// Payment channels allow participants to repeatedly transfer Ether off chain.
+// Here is how this contract is used:
+// - Alice deploys the contract, funding it with some Ether.
+// - Alice authorizes a payment by signing a message (off chain) and sends the signature to Bob.
+// - Bob claims his payment by presenting the signed message to the smart contract.
+// - If Bob does not claim his payment, Alice get her Ether back after the contract expires
+// This is called a uni-directional payment channel since the payment can go only in a single direction from Alice to Bob.
+
+
+import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.5/contracts/utils/cryptography/ECDSA.sol";
+import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.5/contracts/security/ReentrancyGuard.sol";
+
+contract UniDirectionalPaymentChannel is ReentrancyGuard {
+ using ECDSA for bytes32;
+
+ address payable public sender;
+ address payable public receiver;
+
+ uint private constant DURATION = 7 * 24 * 60 * 60;
+ uint public expiresAt;
+
+ constructor(address payable _receiver) payable {
+ require(_receiver != address(0), "receiver = zero address");
+ sender = payable(msg.sender);
+ receiver = _receiver;
+ expiresAt = block.timestamp + DURATION;
+ }
+
+ function _getHash(uint _amount) private view returns (bytes32) {
+ // NOTE: sign with address of this contract to protect agains
+ // replay attack on other contracts
+ return keccak256(abi.encodePacked(address(this), _amount));
+ }
+
+ function getHash(uint _amount) external view returns (bytes32) {
+ return _getHash(_amount);
+ }
+
+ function _getEthSignedHash(uint _amount) private view returns (bytes32) {
+ return _getHash(_amount).toEthSignedMessageHash();
+ }
+
+ function getEthSignedHash(uint _amount) external view returns (bytes32) {
+ return _getEthSignedHash(_amount);
+ }
+
+ function _verify(uint _amount, bytes memory _sig) private view returns (bool) {
+ return _getEthSignedHash(_amount).recover(_sig) == sender;
+ }
+
+ function verify(uint _amount, bytes memory _sig) external view returns (bool) {
+ return _verify(_amount, _sig);
+ }
+
+ function close(uint _amount, bytes memory _sig) external nonReentrant {
+ require(msg.sender == receiver, "!receiver");
+ require(_verify(_amount, _sig), "invalid sig");
+
+ (bool sent, ) = receiver.call{value: _amount}("");
+ require(sent, "Failed to send Ether");
+ selfdestruct(sender);
+ }
+
+ function cancel() external {
+ require(msg.sender == sender, "!sender");
+ require(block.timestamp >= expiresAt, "!expired");
+ selfdestruct(sender);
+ }
+}
diff --git a/basic_knowledge/README.md b/basic_knowledge/README.md
new file mode 100644
index 0000000..e13ec81
--- /dev/null
+++ b/basic_knowledge/README.md
@@ -0,0 +1,1778 @@
+## š¾ solidity (unstructured) tl;dr
+
+
+
+#### ⨠the notes below are a rough overview of solidity from when i started learning it - if you have no idea about the language, it might be a resource to skim - however, you should also check the references on the first page of this repo.
+
+#### ⨠a smart contract is a collection of code (functions) and data (state) on the ethereum blockchain...
+
+
+
+
+----
+
+### the evm
+
+
+
+* the evm is a **stack machine** (not a register machine), so that all computations are performed on the stack data area.
+* the stack has a maximum size of `1024` elements and contains words of `256-bits1.
+* access to the stack is limited to the top end (topmost 16 elements to the top of the stack)
+
+
+
+
+---
+
+### gas
+
+
+
+* gas is a **unit of computation**: each transaction is charged with some gas that has to be paid for by the originator.
+* **gas spent** is the total amount of gas used in a transaction.
+ * if the gas is used up at any point, an out-of-gas exception is triggered, ending execution and reverting all modifications made to the state in the current call frame.
+* since **each block has a maximum amount of gas**, it also limits the amount of work needed to validate a block.
+* **gas price** is how much ether you are willing to pay for gas.
+ * it's set by the originator of the transaction, who has to pay `gas_price * gas` upfront to the EVM executor.
+ * any gas left is refunded to the transaction originator.
+ * exceptions that revert changes do not refund gas.
+* there are **two upper bounds** for the amount of gas you can spend:
+ - **gas limit**: max amount of gas you are willing to use for your transaction, set by you.
+ - **block gas limit**: max amount of gas allowed in a block, set by the network.
+
+
+
+---
+
+### accounts
+
+
+
+* until (**[account abstraction](https://github.com/go-outside-labs/mev-toolkit/tree/main/MEV_by_chains/MEV_on_Ethereum/account_abstraction)** becomes a thing, there are two types of accounts in ethereum: **external accounts** (controlled by a pub-priv key pair and with empty code and storage) and **contract accounts** (controlled by code stored with the account and containing bytecode).
+* these accounts are identified by:
+ * an address of **160-bit length** (rightmost 20 bytes of the **keccak hash** of the RLP encoding of the structure with the sender and the nonce).
+ * a **balance**: in wei, where `1 ether` = `10**18 wei`.
+ * a **nonce**: number of transactions made by the account.
+ * a **bytecode**: merkle root hash of the entire state tree.
+ * **stored data**: a key-value mapping 256-bit words to 256-bit words (*i.e.*, `keccak` hash of the root node of the storage trie).
+
+
+
+---
+
+### transactions
+
+
+
+* as a blockchain is a **globally shared transactional database**, a transaction is a message that is sent from one account to another.
+* anyone can create a transaction to change something in this database.
+* a transaction is **always cryptographically signed by the sender (creator)**.
+* a transaction can include **binary data (payload)** and **ether**.
+* if the **target account contains code**, that **code is executed and the payload is provided as input data**.
+* if the **target account is not set** (*e.g.*, the transaction does not have a recipient or the recipient is set to `null`), the **transaction creates a new contract**.
+ * the address of a new contract is not the zero address, but an **address derived from the sender and its nonce**.
+* the output data of the contract execution is stored as the code contract, *i.e.*, to create a contract, **you don't send the actual code of the contract, but instead a code that returns the code when executed**.
+
+
+
+------
+
+### solidity vs. other languages
+
+
+
+* **from python, we get:**
+ - modifiers
+ - multiple inheritances
+
+* **from js we get:**
+ - function-level scoping
+ - the `var` keyword
+
+* **from c/c++ we get:**
+ - scoping: variables are visible from the point right after their declaration until the end of the smallest {}-block that contains the declaration.
+ - the good ol' value types (passed by value, so they are always copied to the stack) and reference types (references to the same underlying variable).
+ - however, a variable that is declared will have an initial default value whose byte-representation is all zeros.
+ - int and uint integers, with `uint8` to `uint256` in the step of `8`.
+
+* **from being statically-typed:**
+ - the type of each variable (local and state) needs to be specified at compile-time (as opposed to runtime).
+
+* SPDX stands for software package data exchange. the compiler will include this in the bytecode metadata and make it machine readable.
+
+
+
+---
+
+### best practices for layout in a contract
+
+
+
+1. state variables
+2. events
+3. modifiers
+4. constructors
+5. functions
+
+
+
+
+---
+
+### variable scopes
+
+
+
+* `local`, declared and used inside functions and not stored on blockchain.
+* `state`, declared in the contract scope, stored on blockchain.
+* `global`, accessed by all (*e.g.,* `msg.sender`, `block.timestamp`)
+
+
+
+
+---
+
+### variables location
+
+
+
+* variables are declared as either:
+ * **storage**: variable is a state variable (stored on the blockchain).
+ * solidity storage is an array of length `2^256`.
+ * each slot in the array can store 32 bytes.
+ * order of declaration and the type of state variables define which slots it will use, unless you use assembly, then you can write to any slot.
+ * **memory**: byte-array memory (RAM), used to store data during execution (such as passing arguments to internal functions). opcodes are `MSTORE`, `MLOAD`, or `MSTORE8`.
+ * **calldata**: a read-only byte-addressable space for the data parameter of a transaction or call. unlike the stack, this data is accessed by specifying the exact byte offset and the number of bytes to read.
+ * the required gas for disk storage is the most expensive, while storing data to stack is the cheapest.
+
+
+
+-----
+
+
+### predefined global variables and opcodes
+
+
+
+* when a contract is executed in the EVM, it has access to a small set of global objects: `block`, `msg`, and `tx` objects.
+* in addition, solidity exposes a **[number of EVM opcodes](https://ethereum.org/en/developers/docs/evm/opcodes/)** as predefined functions.
+* as we mentioned above, in the evm, all instructions operate on the basic data type, `256-bit` words or on slices of memory (and other byte arrays).
+* the usual arithmetic, bit, logical, and comparison operations are present, and conditional and unconditional jumps are possible.
+* **[list of precompiled contracts](https://www.evm.codes/precompiled?fork=arrowGlacier).**
+
+
+
+
+-----
+
+### `msg`
+
+
+
+* `msg` is a special global variable that contains properties that allow access to the blockchain.
+* `msg object`: the transaction that triggered the execution of the contract.
+* `msg.sender`: sender address of the transaction (*i.e.*, always the address where the current function call come from).
+* `msg.value`: ether sent with this call (in wei).
+* `msg.data`: data payload of this call into our contract.
+* `msg.sig`: first four bytes of the data payload, which is the function selector.
+
+
+
+-----
+
+### `tx`
+
+
+
+* `tx.gasprice`: gas price in the calling transaction.
+* `tx.origin`: address of the originating EOA for this transaction. WARNING: unsafe!
+
+
+
+-----
+
+### `block`
+
+
+
+* `block.coinbase`:
+ * address of the recipient of the current block's fees and block reward.
+ * it's `payable`.
+* `block.gaslimit`: maximum amount of gas that can be spent across all transactions included in the current block.
+* `block.number`: current block number (blockchain height).
+* `block.timestamp`:
+ * timestamp placed in the current block by the miner (number of seconds since the Unix epoch).
+* `block.chainid`
+
+
+
+
+-----
+
+### `address`
+
+
+
+* a state variable can be declared as the type `address`, a `160-bit` value that does not allow arithmetic operations.
+* `address` holds a `20 byte` value (the size of an ethereum address).
+* `address payable` is an address you can send ether to (while plain address is not), and comes with additional members `transfer` and `send`.
+* explicit conversion from address to address payable can be done with `payable()`.
+* explicit conversion from or to address is allowed for `uint160`, integer literals, `byte20`, and contract types.
+* members of address type are:
+ * `address.balance`: balance of the address, in wei.
+ * `address.transfer(__amount__)`: transfers the amount (in wei) to this address, throwing an exception on any error.
+ * `address.send(__amount__)`: similar to transfer, only instead of throwing an exception, it returns false on error.
+ * WARNING: always check the return value of send.
+ * `address.call(__payload__)`: low-level `CALL` functionācan construct an arbitrary message call with a data payload. Returns false on error.
+ * WARNING: unsafe.
+ * `address.delegatecall(__payload__)`: low-level `DELEGATECALL` function, like `callcode(...)` but with the full msg context seen by the current contract. Returns false on error.
+ * WARNING: advanced use only!
+ * `address.code`
+ * `address.codehash`
+ * `address.staticcall`
+
+
+
+---
+
+### built-in functions
+
+* `this`:
+ * address of the currently executing contract account.
+* `addmod`, `mulmod`:
+ * for modulo addition and multiplication. for example, `addmod(x,y,k)` calculates `(x + y) % k`.
+* `keccak256`, `sha256`, `sha3`, `ripemd160`:
+ * calculate hashes with various standard hash algorithms.
+* some `keccak256` use cases are:
+ * to create a deterministic unique ID from a input, for commit-reveal schemes, for compact cryptographic signature (by signing the hash instead of a larger input).
+* `ecrecover`:
+ * recovers the address used to sign a message from the signature:
+ * `erecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)` and can be used to verify a signature:
+ * this will return an `address` of who signed the signature.
+ * `r` is the first 32 bytes of signature
+ * `s` is the second 32 bytes of the signature
+ * `v` is the final ` byte of the signature
+ * the `hash` is the hash of the message the user has signed, with this format:
+```
+hashToBeSuppliedToEcrecover = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n",len(_message), keccak256(_message)));
+```
+* `selfdestruct(__recipient_address__)`:
+ * deletes the current contract, sending any remaining ether in the account to the recipient address (it's the only way to remove code from the blockchain, which can be via delegatecall or callcode).
+ * the `SELFDESTRUCT` opcode is going deprecated/under changes.
+
+
+
+
+---
+
+### pragmas
+
+
+
+* **pragmas** directives are used to enable certain compiler features and checks.
+* `version Pragma` indicates the specific solidity compiler version.
+* it does not change the version of the compiler, though (get an error if it does not match the compiler).
+
+
+
+---
+
+### natspec comments
+
+
+
+* **natspec comments**, also known as the "ethereum natural language specification format".
+* written as triple slashes (`///`) or double asterisk block.
+`(/**...*/)`, directly above function declarations or statements to generate documentation in `JSON` format for developers and end-users.
+* these are some tags:
+ * `@title`: describe the contract/interface
+ * `@author`
+ * `@notice`: explain to an end user what it does
+ * `@dev`: explain to a dev
+ * `@param`: document params
+ * `@return`: any returned variable
+ * `@inheritdoc`: copies missing tags from the base function (must be followed by contract name)
+ * `@custom`: anything application-defined
+
+
+
+---
+
+### events
+
+
+
+* **events** are an abstraction on top of EVM's logging, allowing clients to react to specific contract changes.
+* emitting events cause the arguments to be **stored in the transaction's log** (which are associated with the address of the contract).
+* contracts cannot access log data after it has been created, but they can be efficiently accessed from outside the blockchain (*e.g.*, through bloom filters).
+* some use cases for events are:
+ * listening for events and updating user interface
+ * a cheap form of storage.
+* events are especially useful for light clients and DApp services, which can "watch" for specific events and report them to the user interface, or make a change in the state of the application to reflect an event in an underlying contract.
+* events are created with `event` and emitted with `emit`.
+* for example, an example can be created with:
+
+```
+event Sent(address from, address to, uint amount);
+```
+
+and then, be emitted with:
+
+```
+emit Sent(msg.sender, receiver, amount)
+```
+
+
+
+
+---
+
+### uint
+
+
+
+* `uint` stands for unsigned integer, meaning non-negative integers.
+* different sizes are available:
+ * `uint8` ranges from `0 to 2 ** 8 - 1`
+ * `uint16` ranges from `0 to 2 ** 16 - 1`
+ * `uint256` ranges from `0 to 2 ** 256 - 1`
+
+
+
+
+---
+
+### arrays and byte arrays
+
+
+
+* they can be two types: **fixed-sized arrays** and **dynamically-sized arrays**.
+* the data type `byte` represents a sequence of bytes.
+* `bytes1`, `bytes2`, `bytes3`, ... `bytes32` hold a sequence of bytes from one to up to `32`.
+* the type `byte[]` is an array of bytes that due to padding rules, wastes `31 bytes` of space for each element, therefore it's better to use `bytes()`.
+
+
+
+```
+bytes1 a = 0xb5; // [10110101]
+bytes1 b = 0x56; // [01010110]
+```
+
+
+
+
+---
+
+### state variables
+
+
+
+* variables that can be accessed by all functions of the contract and values are **permanently stored in the contract storage.**
+* state variables can be declared as `public`, `private`, or `internal`, but not `external`.
+
+
+
+---
+
+### what is considered modifying state
+
+
+
+- writing to state variables.
+- emitting events.
+- creating other contracts.
+- sending ether via calls.
+- using selfdestruct.
+- using low-level calls.
+- calling any function not marked `view` or `pure`.
+- using inline assembly that contains certain opcodes.
+
+
+
+
+---
+
+### enum
+
+
+
+* enumerables are useful to model choice and keep track of a state.
+* they are used to create custom types with a finite set of constants values.
+* they cannot have more than 256 members.
+* they can be declared outside of a contract.
+
+
+
+```
+contract Enum {
+ enum Status {
+ Pending,
+ Shipped,
+ Accepted,
+ Rejected,
+ Canceled
+ }
+
+ function cancel() public {
+ status = Status.Canceled;
+ }
+```
+
+
+
+---
+
+
+### structs
+
+
+
+* `structs` are custom-defined types that can group several variables of same/different types together to create a custom data structure.
+* they are a type `byte` also just a template (they need to be declared somewhere else such as a mapping or somtehing to instantiate the actual variable).
+* you can define your own type by creating a `struct`, and they are useful for grouping together related data.
+* structs can be declared outside of a contract and imported into another contract.
+
+
+
+```
+contract Todos {
+ struct Todo {
+ string text;
+ bool completed;
+ }
+
+ Todo[] public todos;
+
+ function create(string calldata _text) public {
+ todos.push(todo);
+ }
+}
+```
+
+
+
+---
+
+### immutability
+
+
+
+* state variables can be declared as constant or immutable, so they cannot be modified after the contract has been constructed.
+ * for **constant variables**, the value is fixed at compile-time.
+ * for **immutable variables**, the value can still be assigned at construction time (in the constructor or point of declaration).
+ * for **constant variables**, the expression assigned is copied to all the places, and re-evaluated each time (local optimizations are possible).
+ * for **immutable variables**, the expression is evaluated once at constriction time and their value is copied to all the places in the code they are accessed, on a reserved `32 bytes`, becoming usually more expensive than constant.
+* example:
+
+
+
+```
+contract Immutable {
+ address public immutable MY_ADDRESS;
+ uint public immutable MY_UINT;
+
+ constructor(uint _someUint) {
+ MY_ADDRESS = msg.sender;
+ MY_UINT = _someUint;
+ }
+}
+```
+
+
+
+---
+
+### functions modifiers
+
+
+
+* used to change the behavior of functions in a declarative way, so that the function's control flow continues after the "_" in the preceding modifier.
+* the underscore followed by a semicolon is a placeholder that is replaced by the code of the function that is being modified. the modifier is "wrapped around" the modified function, placing its code in the location identified by the underscore character.
+* to apply a modifier, you add its name to the function declaration.
+* more than one modifier can be applied to a function; they are applied in the sequence they are declared, as a space-separated list.
+
+```
+function destroy() public onlyOwner {
+```
+
+
+
+
+---
+
+
+### state visibility specifiers
+
+
+
+* define how the methods will be accessed.
+* `public`:
+ * any contract and account can call.
+* `external`:
+ * only other contracts and accounts can call.
+ * an external function `func` cannot be called internally: `func()` does not work but `this.func()` does.
+* `internal`:
+ * can only be accessed internally from within the current contracts (or contracts deriving from it with `internal` function).
+* `private`:
+ * can only be accessed from the contract where the function is defined (not in derived contracts).
+* `payable`:
+ * can accept incoming ether payments.
+ * functions not declared as payable will reject incoming payments.
+ * there are two exceptions, due to design decisions in the EVM: coinbase payments and `SELFDESTRUCT` inheritance will be paid even if the fallback function is not declared as payable.
+
+
+
+----
+
+### function mutability specifiers
+
+
+
+* getter functions can be declared `view` or `pure:
+ * `view` functions declares that no state will be changed.
+ * they can read the contract state but not modify it.
+ * they are enforced at runtime via `STATICALL` opcode.
+ * `pure` functions declares that no state variable can be changed or read.
+ * they can neither read a contract nor modify it.
+ * pure functions are intended to encourage declarative-style programming without side effects or state.
+* only `view` can be enforced at the EVM level, not `pure`.
+
+
+
+---
+
+### function selectors
+
+
+
+* when a function is called, the function selector (represented by the first 4 bytes of `calldata`) specifies which functions to call.
+* for instance, in the example below, `call` is used to execute `transfer` on a contract at the address `addr` and the first 4 bytes returned from `abi.encondeWithSignature()` is the function selector:
+
+```
+addr.call(abi.encodeWithSignature("transfer(address,uint256)", 0xSomeAddress, 123))
+```
+
+* you can save gas by precomputing and inline the function selector:
+
+```
+contract FunctionSelector {
+ /*
+ "transfer(address,uint256)"
+ 0xa9059cbb
+ "transferFrom(address,address,uint256)"
+ 0x23b872dd
+ */
+ function getSelector(string calldata _func) external pure returns (bytes4) {
+ return bytes4(keccak256(bytes(_func)));
+ }
+}
+```
+
+
+
+
+---
+
+### overloading
+
+
+
+* a contract can have multiple functions of the same name but with different parameter types.
+* they are matched by the arguments supplied in the function call.
+
+
+
+
+---
+
+### constructors
+
+
+
+* a constructor is an optional function that only run when the contract is created (it cannot be called afterwards).
+* a global variable can be the assigned to the contractor creator by attributing `msg.sender` to it.
+* when a contract is created, the function with **constructor** is executed once and then the final code of the contract is stored on the blockchain (all public and external functions, but not the constructor code or internal functions called by it).
+
+
+
+----
+
+### error handling
+
+
+
+* there are two kinds of errors that EVM can throw. `Error` and `Panic`.
+* an error will undo all changes made to the state during a transaction and they are returned to the caller of the function, example:
+
+```
+error InsufficientBalance(uint requested, uint available);
+```
+
+* errors are used together with the `revert statement`, which unconditionally aborts and reverts all changes.
+* errors can also provide information about a failed operations.
+* you can throw an error by calling:
+ - `assert()`: used to check for code that should never be false. causes a panic error and reverts if the condition is not met.
+ - `require()`: used to validate inputs and conditions before execution. reverts if the condition is not met.
+ - `revert()`: similar to require. abort execution and revert state changes.
+* `try / catch` can only catch errors from external functions and contract creation.
+
+
+
+
+----
+
+### if / else
+
+
+
+```
+contract IfElse {
+
+ function foo(uint x) public pure returns (uint) {
+ if (x < 10) {
+ return 0;
+ } else if (x < 20) {
+ return 1;
+ } else {
+ return 2;
+ }
+ }
+
+ function ternary(uint _x) public pure returns (uint) {
+ // shorthand way to write if / else statement
+ // the "?" operator is called the ternary operator
+ return _x < 10 ? 1 : 2;
+ }
+}
+````
+
+
+
+----
+
+### for and while loops
+
+
+
+```
+contract Loop {
+ function loop() public {
+ // FOR LOOP
+ for (uint i = 0; i < 10; i++) {
+ if (i == 3) {
+ // Silly example to show how to skip to next iteration
+ continue;
+ }
+ if (i == 5) {
+ // Exit loop
+ break;
+ }
+ }
+
+ // WHILE LOOP
+ uint j;
+ while (j < 10) {
+ j++;
+ }
+ }
+}
+```
+
+
+
+---
+
+### function modifiers
+
+
+
+* modifiers are code that can be run before and/or after a function call.
+* underscore is a special character only used inside function modifier and it tells solidity to execute the rest of the code.
+
+
+
+----
+
+### restricted access
+
+
+
+* check that the caller is the owner of the contract.
+
+
+```
+// Modifier to check that the caller is the owner of the contract.
+modifier onlyOwner() {
+ require(msg.sender == owner, "Not owner");
+ _;
+}
+```
+
+
+
+---
+
+### validating inputs
+
+
+
+* check that the address passed is not in the zero address.
+
+```
+// 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;
+}
+```
+
+
+
+---
+
+### guarding against reentrancy attack
+
+
+
+* prevents a function from being called while it's still executing.
+
+```
+// 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);
+ }
+ }
+```
+
+
+
+----
+
+### inheritance
+
+
+
+* solidity supports multiple inheritance, and their order is important (i.e., list the parent contracts in the order from most base-like to most derived).
+* contracts can inherit other contract by using the `is` keyword.
+* function that is going to be overridden by a child contract must be declared as `virtual`.
+* function that is going to override a parent function must use the keyword `override`.
+
+
+
+```
+/* Graph of inheritance
+ A
+ / \
+ B C
+ / \ /
+F D,E
+
+*/
+
+contract A {
+ function foo() public pure virtual returns (string memory) {
+ return "A";
+ }
+}
+
+// Contracts inherit other contracts by using the keyword 'is'.
+contract B is A {
+ // Override A.foo()
+ function foo() public pure virtual override returns (string memory) {
+ return "B";
+ }
+}
+
+contract C is A {
+ // Override A.foo()
+ function foo() public pure virtual override returns (string memory) {
+ return "C";
+ }
+}
+
+// Contracts can inherit from multiple parent contracts.
+// When a function is called that is defined multiple times in
+// different contracts, parent contracts are searched from
+// right to left, and in depth-first manner.
+
+contract D is B, C {
+ // D.foo() returns "C"
+ // since C is the right most parent contract with function foo()
+ function foo() public pure override(B, C) returns (string memory) {
+ return super.foo();
+ }
+}
+
+contract E is C, B {
+ // E.foo() returns "B"
+ // since B is the right most parent contract with function foo()
+ function foo() public pure override(C, B) returns (string memory) {
+ return super.foo();
+ }
+}
+
+// Inheritance must be ordered from āmost base-likeā to āmost derivedā.
+// Swapping the order of A and B will throw a compilation error.
+contract F is A, B {
+ function foo() public pure override(A, B) returns (string memory) {
+ return super.foo();
+ }
+}
+```
+
+
+
+---
+
+### shadowing inherited state variables
+
+
+
+* unlike functions, state variables cannot be overridden by re-declaring in the child contract.
+* this is how inherited state variables can be overridden:
+
+
+
+```
+contract A {
+ string public name = "Contract A";
+
+ function getName() public view returns (string memory) {
+ return name;
+ }
+}
+
+// Shadowing is disallowed in Solidity 0.6
+// This will not compile
+// contract B is A {
+// string public name = "Contract B";
+// }
+
+contract C is A {
+ // This is the correct way to override inherited state variables.
+ constructor() {
+ name = "Contract C";
+ }
+
+ // C.getName returns "Contract C"
+}
+```
+
+
+
+---
+
+### calling parent contracts
+
+
+
+* parent contracts can be called directly, or by using the word `super`.
+* if using the keyword `super`, all of the intermediate parent contracts are called.
+
+
+
+
+---
+
+### interfaces
+
+
+
+* interfaces are a way to interact with other contracts.
+* they cannot have any functions implemented, declare a constructor, or declare state variables.
+* they can inherit from other interfaces.
+* all declared functions must be external.
+
+```
+contract Counter {
+ uint public count;
+
+ function increment() external {
+ count += 1;
+ }
+}
+
+interface ICounter {
+ function count() external view returns (uint);
+
+ function increment() external;
+}
+
+contract MyContract {
+ function incrementCounter(address _counter) external {
+ ICounter(_counter).increment();
+ }
+
+ function getCount(address _counter) external view returns (uint) {
+ return ICounter(_counter).count();
+ }
+}
+
+// Uniswap example
+interface UniswapV2Factory {
+ function getPair(
+ address tokenA,
+ address tokenB
+ ) external view returns (address pair);
+}
+
+interface UniswapV2Pair {
+ function getReserves()
+ external
+ view
+ returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
+}
+
+contract UniswapExample {
+ address private factory = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;
+ address private dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
+ address private weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
+
+ function getTokenReserves() external view returns (uint, uint) {
+ address pair = UniswapV2Factory(factory).getPair(dai, weth);
+ (uint reserve0, uint reserve1, ) = UniswapV2Pair(pair).getReserves();
+ return (reserve0, reserve1);
+ }
+}
+```
+
+
+
+---
+
+### libraries
+
+
+
+* libraries are similar to contracts, but you can't declare any state variable and can't send ether.
+* a library is embedded into the contract if all library functions are internal, otherwise the library must be deployed and then linked before the contract is deployed.
+
+
+
+---
+
+### ABI encode and decode
+
+
+
+* `abi.encode` encodes data into bytes.
+
+
+
+```
+interface IERC20 {
+ function transfer(address, uint) external;
+}
+
+contract Token {
+ function transfer(address, uint) external {}
+}
+
+contract AbiEncode {
+ function test(address _contract, bytes calldata data) external {
+ (bool ok, ) = _contract.call(data);
+ require(ok, "call failed");
+ }
+
+ function encodeWithSignature(
+ address to,
+ uint amount
+ ) external pure returns (bytes memory) {
+ // Typo is not checked - "transfer(address, uint)"
+ return abi.encodeWithSignature("transfer(address,uint256)", to, amount);
+ }
+
+ function encodeWithSelector(
+ address to,
+ uint amount
+ ) external pure returns (bytes memory) {
+ // Type is not checked - (IERC20.transfer.selector, true, amount)
+ return abi.encodeWithSelector(IERC20.transfer.selector, to, amount);
+ }
+
+ function encodeCall(address to, uint amount) external pure returns (bytes memory) {
+ // Typo and type errors will not compile
+ return abi.encodeCall(IERC20.transfer, (to, amount));
+ }
+}
+```
+
+
+
+* `abi.decode` decodes bytes back into data.
+
+
+
+```
+contract AbiDecode {
+ struct MyStruct {
+ string name;
+ uint[2] nums;
+ }
+
+ function encode(
+ uint x,
+ address addr,
+ uint[] calldata arr,
+ MyStruct calldata myStruct
+ ) external pure returns (bytes memory) {
+ return abi.encode(x, addr, arr, myStruct);
+ }
+
+ function decode(
+ bytes calldata data
+ )
+ external
+ pure
+ returns (uint x, address addr, uint[] memory arr, MyStruct memory myStruct)
+ {
+ // (uint x, address addr, uint[] memory arr, MyStruct myStruct) = ...
+ (x, addr, arr, myStruct) = abi.decode(data, (uint, address, uint[], MyStruct));
+ }
+}
+```
+
+
+
+
+-----
+
+### sending and receiving ether
+
+
+
+* you can send ether to other contracts by:
+ * `transfer` (2300 gas, throws error)
+ * `send` (2300 gas, returns bool)
+ * `call` (forwards all gas or ser gas, returns bool), should be used with re-entrancy guard (i.e., by making all state changes before calling other contracts, and by using re-entrancy guard modifier)
+
+* a contract receiving ether must have at least of the functions below:
+ * `receive() external payable`, called if `msg.data` is empty, otherwise `fallback()` is called
+ * `fallback() external payable`
+
+
+```
+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");
+ }
+}
+```
+
+
+
+---
+
+### receive function
+
+
+
+* a contract can have ONE **receive** function (`receive() external payable {...}`, without the function keyword, and no arguments and no return).
+* the `external` and `payable` are the functions on where ether is transfered via `send()` or `transfer()`.
+* receive is executed on a call to the contract with empty calldata.
+* receive might only rely on 2300 gas being available.
+* a contract without receive can still receive ether as a recipient of a coinbase transaction (miner block reward) or as a destination of `selfdestruct` (a contract cannot react to this ether transfer).
+
+
+
+---
+
+
+### falback function
+
+
+
+* `fallback` is a special function that is executed on a call to the contract when:
+ * a function that does not exist is called (no function match the function signature).
+ * ether is sent directly to a contract but `receive()` does not exist or `msg.data` is not empty.
+* a contract can have only one `fallback` function, which must have `external` visibility.
+* `fallback` has 2300 gas limit when called by `transfer` or `send`.
+* `fallback` can take `bytes` for input or output.
+
+
+
+
+```
+// TestFallbackInputOutput -> FallbackInputOutput -> Counter
+contract FallbackInputOutput {
+ address immutable target;
+
+ constructor(address _target) {
+ target = _target;
+ }
+
+ fallback(bytes calldata data) external payable returns (bytes memory) {
+ (bool ok, bytes memory res) = target.call{value: msg.value}(data);
+ require(ok, "call failed");
+ return res;
+ }
+}
+
+contract Counter {
+ uint public count;
+
+ function get() external view returns (uint) {
+ return count;
+ }
+
+ function inc() external returns (uint) {
+ count += 1;
+ return count;
+ }
+}
+
+contract TestFallbackInputOutput {
+ event Log(bytes res);
+
+ function test(address _fallback, bytes calldata data) external {
+ (bool ok, bytes memory res) = _fallback.call(data);
+ require(ok, "call failed");
+ emit Log(res);
+ }
+
+ function getTestData() external pure returns (bytes memory, bytes memory) {
+ return (abi.encodeCall(Counter.get, ()), abi.encodeCall(Counter.inc, ()));
+ }
+}
+```
+
+
+
+
+---
+
+### transfer() function
+
+
+
+* the transfer function fails if the balance of the contract is not enough or if the transfer is rejected by the receiving account.
+
+
+
+---
+
+### send() function
+
+
+
+* low-level counterpart of transfer. if the execution fails, then send returns false.
+* the return value must be checked by the caller.
+
+
+
+----
+
+### data management
+
+
+
+* the evm manages different kinds of data depending on their context.
+
+
+
+----
+
+### stack
+
+
+
+* the evm operates on a virtual stack, which has a maximum size of `1024`.
+* stack items have a size of `256 bits` (the evm is a `256-bit` word machine, which facilitates keccak256 hash scheme and elliptic-curve).
+* the opcodes to modify the stack are:
+ * `POP` (remove from stack),
+ * `PUSH n` (places the `n` bytes item into the stack),
+ * `DUP n` (duplicates the `n`th stack item),
+ * `SWAP n` (exchanges the first and the `n`th stack item).
+
+
+
+
+
+---
+
+### calldata
+
+
+
+* a called contract receive a freshly cleared instance of memory and has access to the call payload, provided in a separate area called the **calldata**.
+* after it finishes execution, it can return data which will be stored at a location in the caller's memory preallocated by the caller.
+* opcodes include: `CALLDATASIZE` (get size of tx data), `CALLDATALOAD` (loads 32 byte of tx data onto the stack), `CALLDATACOPY` (copies the number of bytes of the tx data to memory).
+* there are also the inline assembly versions: `calldatasize`, `calldataload`, calldatacopy`.
+* they can be called through:
+
+```
+assembly {
+(...)
+}
+```
+
+
+
+---
+
+### storage
+
+
+
+* persistent read-write word-addressable space for contracts, addressed by words.
+* storage a key-value mapping of `2**256 `slots of `32-bytes` each.
+* gas to save data into storage is one of the highest operations.
+* the evm opcodes are: `SLOAD` (loads a word from storage to stack), `SSTORE` (saves a word to storage).
+* it's costly to read, initialise, and modify storage.
+* a contract cannot read or write to any storage apart from its own.
+
+
+
+---
+
+### type of storages
+
+
+
+* bitpack loading: storing multiple variables in a single `32-bytes` slot by ordering the byte size.
+* fixed-length arrays: takes a predetermined amount of slots.
+* dynamic-length arrays: new elements assign slots after deployment (handled by the evm with keccak256 hashing).
+* mappings: dynamic type with key hashes.
+ * for example, `mapping(address => int)` maps unsigned integers.
+ * can only be defined in storage (*i.e.,* state variables). memory does not allow mappings even if they are inside a `struct`.
+ * the key type can be any built-in value type, bytes, string, or any contract.
+ * value type can be any type including another mapping or an array.
+ * mapping are not iterable: it's not possible to obtain a list of all keys of a mapping, nor a list of all values.
+ * maps cannot be used for functions input or output.
+
+
+
+
+```
+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];
+ }
+}
+```
+
+
+
+---
+
+### memory
+
+
+
+* the second data area of which a contract obtains a cleared instance for each message call.
+* memory is linear and can be addressed at the byte level.
+* reads are limited to a width of `256 bit`s, while writes can be either `8 bits` or `256 bits` wide.
+* memory is expanded by a word (`256-bit`), when accessing (either reading or writing) a previously untouched memory.
+* at the time of expansion, the cost of gas must be paid - memory is more costly the large it grows, scaling quadratically.
+* volatile read-write byte-addressable space (store data during execution) initialized as zero.
+* the evm opcodes are `MLOAD` (loads a word into the stack), `MSTORE` (saves a word to memory), `MSTORE8` (saves a byte to memory).
+* gas costs for memory loads (`MLOADs`) are significantly cheaper in gas than `SLOADs`.
+
+
+
+
+
+
+----
+
+
+### contract creation (`CREATE2`)
+
+
+
+* the **creation of a contract** is a transaction where the **receiver address is empty** and its **data field contains compiled bytecode** or calling `CREATE2` opcode.
+* the `new` keyword supports `CREATE2` feature by specifying `salt` options.
+* the data sent is executed as bytecode, initializing the state variables in storage and determining the body of the contract being created.
+* **contract memory** is a byte array, where data can be stored in `32 bytes (256 bit)` or `1 byte (8 bit)` chunks, reading in `32 bytes` chunks (through `MSTORE`, `MLOAD`, `MSTORE8`).
+
+
+
+---
+
+### message calls (`CALL`)
+
+
+
+* `call` is a low-level function to **interact with other contracts**.
+* contracts can call other contracts or send ether to non-contract accounts by through **message calls** (`CALL` opcode).
+* every call has a **sender**, a **recipient**, a **payload** (data), a **value** (in wei), and some **gas**.
+* it's the **recommended method** to use when **just sending ether via calling the `fallback` function**.
+* but it's **not the recommended way** to call **existing functions**:
+ * reverts are not bubbled up.
+ * type checks are bypassed.
+ * function existence checks are omitted.
+* a contract can decide how much of its remaining gas should be sent with the inner message call and how much it wants to retain.
+* message calls are limited to a depth of `1024`, which means that for more complex operations, loops should be preferred over recursive calls.
+* this is the recommended way of calling a contract:
+
+```
+contract Callee {
+ uint public x;
+ uint public value;
+
+ function setX(uint _x) public returns (uint) {
+ x = _x;
+ return x;
+ }
+
+ function setXandSendEther(uint _x) public payable returns (uint, uint) {
+ x = _x;
+ value = msg.value;
+
+ return (x, value);
+ }
+}
+
+contract Caller {
+ function setX(Callee _callee, uint _x) public {
+ uint x = _callee.setX(_x);
+ }
+
+ function setXFromAddress(address _addr, uint _x) public {
+ Callee callee = Callee(_addr);
+ callee.setX(_x);
+ }
+
+ function setXandSendEther(Callee _callee, uint _x) public payable {
+ (uint x, uint value) = _callee.setXandSendEther{value: msg.value}(_x);
+ }
+}
+```
+
+
+
+----
+
+### delegate call (`DELEGATECALL`)
+
+
+
+* `DELEGATECALL` preserves context (storage, caller, etc...) of the origing contract, where target code is executed within this context (`address`). therefore, `msg.sender` and `msg.value` do not change.
+
+```
+when contract A executes delegatecall to contract B:
+B's code is executed with contract A's storage, msg.sender and msg.value
+```
+
+* **storage layout must be the same** for the contract calling delegatecall and the contract getting called.
+
+* the contract can **dynamically load code (storage) from a different address at runtime**, while the **current address and balance still refer to the calling contract**.
+
+* when a contract is being created, the code is still empty. the contract is under construction until the constuctor has finished executing.
+
+
+
+```
+// 1. Deploy this contract first
+contract B {
+ // NOTE: storage layout must be the same as contract A
+ uint public num;
+ address public sender;
+ uint public value;
+
+ function setVars(uint _num) public payable {
+ num = _num;
+ sender = msg.sender;
+ value = msg.value;
+ }
+}
+
+contract A {
+ uint public num;
+ address public sender;
+ uint public value;
+
+ function setVars(address _contract, uint _num) public payable {
+ // A's storage is set, B is not modified.
+ (bool success, bytes memory data) = _contract.delegatecall(
+ abi.encodeWithSignature("setVars(uint256)", _num)
+ );
+ }
+}
+```
+
+
+
+
+---
+
+### call / delegatecall/ statcall
+
+
+
+* used to interface with contracts that do not adhere to ABI, or to give more direct control over encoding.
+* they all take a single bytes memory parameter and return the success condition (as a bool) and the return data (byte memory).
+* with `DELEGATECALL`, only the code of the given address is used but all other aspects are taken from the current contract. the purpose is to use logic code that is stored in the callee contract but operates on the state of the caller contract.
+* with `STATCALL`, the execution will revert if the called function modifies the state in any way.
+
+
+
+---
+
+### creating a new instance
+
+
+
+* the safest way to call another contract is if you create that other contract yourself.
+* to do this, you can simply instantiate it, using the keyword `new`, as in other object-oriented languages.
+* this keyword will create the contract on the blockchain and return an object that you can use to reference it.
+
+```
+contract Token is Mortal {
+ Faucet _faucet;
+
+ constructor() {
+ _faucet = new Faucet();
+ }
+}
+```
+
+
+
+---
+
+### addressing an existing instance
+
+
+
+* another way you can call a contract is by casting the address of an existing instance of the contract.
+* with this method, you apply a known interface to an existing instance.
+* this is much riskier than the previous mechanism, because we donāt know for sure whether that address actually is a faucet object.
+
+```
+import "Faucet.sol";
+
+contract Token is Mortal {
+
+ Faucet _faucet;
+
+ constructor(address _f) {
+ _faucet = Faucet(_f);
+ _faucet.withdraw(0.1 ether);
+ }
+}
+
+```
+
+
+
+
+----
+
+### randomness
+
+
+
+* you cannot rely on `block.timestamp` or `blockhash` as a source of randomness.
+* here is a snippet of an attack:
+
+```/*
+GuessTheRandomNumber is a game where you win 1 Ether if you can guess the
+pseudo random number generated from block hash and timestamp.
+
+At first glance, it seems impossible to guess the correct number.
+But let's see how easy it is win.
+
+1. Alice deploys GuessTheRandomNumber with 1 Ether
+2. Eve deploys Attack
+3. Eve calls Attack.attack() and wins 1 Ether
+
+What happened?
+Attack computed the correct answer by simply copying the code that computes the random number.
+*/
+
+contract GuessTheRandomNumber {
+ constructor() payable {}
+
+ function guess(uint _guess) public {
+ uint answer = uint(
+ keccak256(abi.encodePacked(blockhash(block.number - 1), block.timestamp))
+ );
+
+ if (_guess == answer) {
+ (bool sent, ) = msg.sender.call{value: 1 ether}("");
+ require(sent, "Failed to send Ether");
+ }
+ }
+}
+
+contract Attack {
+ receive() external payable {}
+
+ function attack(GuessTheRandomNumber guessTheRandomNumber) public {
+ uint answer = uint(
+ keccak256(abi.encodePacked(blockhash(block.number - 1), block.timestamp))
+ );
+
+ guessTheRandomNumber.guess(answer);
+ }
+
+ // Helper function to check balance
+ function getBalance() public view returns (uint) {
+ return address(this).balance;
+ }
+}
+```
+
+
+
+---
+
+
+### ABI encoding and decoding functions
+
+
+
+- `abi.decode`:
+ - `(uint a, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes))` decodes the abi encoded data.
+- `abi.encode`:
+ - `abi.encode(...)` returns `(bytes memory)` encodes stuff using padding and hence no collisions when dynamic data is involved.
+- `abi.encodePacked`:
+ - `abi.encodePacked(...)` returns `(bytes memory) does packed encoding.
+ - NOT be used when >2 dynamic arguments are involved due to hash collision. for instance, A, AB and AA, B give the same encoding due to no padding.
+- `abi.encodeWithSelector`:
+ - `abi.encodeWithSelector(bytes4 selector, ...)` returns `(bytes memory)` same as `abi.encode` but prepends the selector.
+ - this is useful when doing raw txns, selector is used to specify function signature.
+- `abi.encodeCall`:
+ - `abi.encodeCall(functionPointer, ...)` returns `(byte memory)`, the same as above but a function pointer is passed.
+- `abi.encodeWithSignature`
+
+
+
+
+----
+
+### signatures
+
+
+
+* messages can be signed off chain and then verified on chain using a smart contract.
+* messages are signed with the following steps:
+ 1. create a message to sign
+ 2. hash the messahe
+ 3. sign the hash (off chain, keep private key secret)
+ * messages can be signed with the following steps:
+ 1. recreate hash from the original message
+ 2. recover signed from signature and hash
+ 3. compare recovered signed to claimed signer
+
+
+
+
+
+```
+contract VerifySignature {
+ /* 1. Unlock MetaMask account
+ ethereum.enable()
+ */
+
+ /* 2. Get message hash to sign
+ getMessageHash(
+ 0x14723A09ACff6D2A60DcdF7aA4AFf308FDDC160C,
+ 123,
+ "coffee and donuts",
+ 1
+ )
+
+ hash = "0xcf36ac4f97dc10d91fc2cbb20d718e94a8cbfe0f82eaedc6a4aa38946fb797cd"
+ */
+ function getMessageHash(
+ address _to,
+ uint _amount,
+ string memory _message,
+ uint _nonce
+ ) public pure returns (bytes32) {
+ return keccak256(abi.encodePacked(_to, _amount, _message, _nonce));
+ }
+
+ /* 3. Sign message hash
+ # using browser
+ account = "copy paste account of signer here"
+ ethereum.request({ method: "personal_sign", params: [account, hash]}).then(console.log)
+
+ # using web3
+ web3.personal.sign(hash, web3.eth.defaultAccount, console.log)
+
+ Signature will be different for different accounts
+ 0x993dab3dd91f5c6dc28e17439be475478f5635c92a56e17e82349d3fb2f166196f466c0b4e0c146f285204f0dcb13e5ae67bc33f4b888ec32dfe0a063e8f3f781b
+ */
+ function getEthSignedMessageHash(
+ bytes32 _messageHash
+ ) public pure returns (bytes32) {
+ /*
+ Signature is produced by signing a keccak256 hash with the following format:
+ "\x19Ethereum Signed Message\n" + len(msg) + msg
+ */
+ return
+ keccak256(
+ abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash)
+ );
+ }
+
+ /* 4. Verify signature
+ signer = 0xB273216C05A8c0D4F0a4Dd0d7Bae1D2EfFE636dd
+ to = 0x14723A09ACff6D2A60DcdF7aA4AFf308FDDC160C
+ amount = 123
+ message = "coffee and donuts"
+ nonce = 1
+ signature =
+ 0x993dab3dd91f5c6dc28e17439be475478f5635c92a56e17e82349d3fb2f166196f466c0b4e0c146f285204f0dcb13e5ae67bc33f4b888ec32dfe0a063e8f3f781b
+ */
+ function verify(
+ address _signer,
+ address _to,
+ uint _amount,
+ string memory _message,
+ uint _nonce,
+ bytes memory signature
+ ) public pure returns (bool) {
+ bytes32 messageHash = getMessageHash(_to, _amount, _message, _nonce);
+ bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash);
+
+ return recoverSigner(ethSignedMessageHash, signature) == _signer;
+ }
+
+ function recoverSigner(
+ bytes32 _ethSignedMessageHash,
+ bytes memory _signature
+ ) public pure returns (address) {
+ (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);
+
+ return ecrecover(_ethSignedMessageHash, v, r, s);
+ }
+
+ function splitSignature(
+ bytes memory sig
+ ) public pure returns (bytes32 r, bytes32 s, uint8 v) {
+ require(sig.length == 65, "invalid signature length");
+
+ assembly {
+ /*
+ First 32 bytes stores the length of the signature
+
+ add(sig, 32) = pointer of sig + 32
+ effectively, skips first 32 bytes of signature
+
+ mload(p) loads next 32 bytes starting at the memory address p into memory
+ */
+
+ // first 32 bytes, after the length prefix
+ r := mload(add(sig, 32))
+ // second 32 bytes
+ s := mload(add(sig, 64))
+ // final byte (first byte of the next 32 bytes)
+ v := byte(0, mload(add(sig, 96)))
+ }
+
+ // implicitly return (r, s, v)
+ }
+}
+```
+
+
+
+---
+
+### global units
+
+
+
+* `ether`, `wei`, `gwei` are global keywods:
+
+```
+assert(1 wei == 1);
+assert(1 gwei == 1e9);
+assert(1 ether == 1e18);
+```
+
+* `gasleft()` returns gas left in the current call.
+* properties like `tx.*` and `block.*` might not be accurate when executed off-chain (not in an actual block).
+
+
+
+
+---
+
+### final consideration and tricks
+
+
+
+* you can compare two dynamic length `bytes` or `string` by using `keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2))`.
+* string does not have length property to access it's length. to make it usable in code that relies on length, cast it to `byte`s with `bytes(string)`.
+
+
+
diff --git a/basic_knowledge/bitwise.md b/basic_knowledge/bitwise.md
new file mode 100644
index 0000000..343c659
--- /dev/null
+++ b/basic_knowledge/bitwise.md
@@ -0,0 +1,200 @@
+## bitwise operators
+
+
+
+### example of bitwise operations
+
+```
+contract BitwiseOps {
+ // x = 1110 = 8 + 4 + 2 + 0 = 14
+ // y = 1011 = 8 + 0 + 2 + 1 = 11
+ // x & y = 1010 = 8 + 0 + 2 + 0 = 10
+ function and(uint x, uint y) external pure returns (uint) {
+ return x & y;
+ }
+
+ // x = 1100 = 8 + 4 + 0 + 0 = 12
+ // y = 1001 = 8 + 0 + 0 + 1 = 9
+ // x | y = 1101 = 8 + 4 + 0 + 1 = 13
+ function or(uint x, uint y) external pure returns (uint) {
+ return x | y;
+ }
+
+ // x = 1100 = 8 + 4 + 0 + 0 = 12
+ // y = 0101 = 0 + 4 + 0 + 1 = 5
+ // x ^ y = 1001 = 8 + 0 + 0 + 1 = 9
+ function xor(uint x, uint y) external pure returns (uint) {
+ return x ^ y;
+ }
+
+ // x = 00001100 = 0 + 0 + 0 + 0 + 8 + 4 + 0 + 0 = 12
+ // ~x = 11110011 = 128 + 64 + 32 + 16 + 0 + 0 + 2 + 1 = 243
+ function not(uint8 x) external pure returns (uint8) {
+ return ~x;
+ }
+
+ // 1 << 0 = 0001 --> 0001 = 1
+ // 1 << 1 = 0001 --> 0010 = 2
+ // 1 << 2 = 0001 --> 0100 = 4
+ // 1 << 3 = 0001 --> 1000 = 8
+ // 3 << 2 = 0011 --> 1100 = 12
+ function shiftLeft(uint x, uint bits) external pure returns (uint) {
+ return x << bits;
+ }
+
+ // 8 >> 0 = 1000 --> 1000 = 8
+ // 8 >> 1 = 1000 --> 0100 = 4
+ // 8 >> 2 = 1000 --> 0010 = 2
+ // 8 >> 3 = 1000 --> 0001 = 1
+ // 8 >> 4 = 1000 --> 0000 = 0
+ // 12 >> 1 = 1100 --> 0110 = 6
+ function shiftRight(uint x, uint bits) external pure returns (uint) {
+ return x >> bits;
+ }
+
+ // Get last n bits from x
+ function getLastNBits(uint x, uint n) external pure returns (uint) {
+ // Example, last 3 bits
+ // x = 1101 = 13
+ // mask = 0111 = 7
+ // x & mask = 0101 = 5
+ uint mask = (1 << n) - 1;
+ return x & mask;
+ }
+
+ // Get last n bits from x using mod operator
+ function getLastNBitsUsingMod(uint x, uint n) external pure returns (uint) {
+ // 1 << n = 2 ** n
+ return x % (1 << n);
+ }
+
+ // Get position of most significant bit
+ // x = 1100 = 10, most significant bit = 1000, so this function will return 3
+ function mostSignificantBit(uint x) external pure returns (uint) {
+ uint i = 0;
+ while ((x >>= 1) > 0) {
+ ++i;
+ }
+ return i;
+ }
+
+ // Get first n bits from x
+ // len = length of bits in x = position of most significant bit of x, + 1
+ function getFirstNBits(uint x, uint n, uint len) external pure returns (uint) {
+ // Example
+ // x = 1110 = 14, n = 2, len = 4
+ // mask = 1100 = 12
+ // x & mask = 1100 = 12
+ uint mask = ((1 << n) - 1) << (len - n);
+ return x & mask;
+ }
+}
+```
+
+
+
+----
+
+### most significant bit
+
+
+
+```
+contract MostSignificantBitFunction {
+ // Find most significant bit using binary search
+ function mostSignificantBit(uint x) external pure returns (uint msb) {
+ // x >= 2 ** 128
+ if (x >= 0x100000000000000000000000000000000) {
+ x >>= 128;
+ msb += 128;
+ }
+ // x >= 2 ** 64
+ if (x >= 0x10000000000000000) {
+ x >>= 64;
+ msb += 64;
+ }
+ // x >= 2 ** 32
+ if (x >= 0x100000000) {
+ x >>= 32;
+ msb += 32;
+ }
+ // x >= 2 ** 16
+ if (x >= 0x10000) {
+ x >>= 16;
+ msb += 16;
+ }
+ // x >= 2 ** 8
+ if (x >= 0x100) {
+ x >>= 8;
+ msb += 8;
+ }
+ // x >= 2 ** 4
+ if (x >= 0x10) {
+ x >>= 4;
+ msb += 4;
+ }
+ // x >= 2 ** 2
+ if (x >= 0x4) {
+ x >>= 2;
+ msb += 2;
+ }
+ // x >= 2 ** 1
+ if (x >= 0x2) msb += 1;
+ }
+}
+```
+
+
+
+----
+
+### most significant bit in assembly
+
+
+
+```
+contract MostSignificantBitAssembly {
+ function mostSignificantBit(uint x) external pure returns (uint msb) {
+ assembly {
+ let f := shl(7, gt(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
+ x := shr(f, x)
+ // or can be replaced with add
+ msb := or(msb, f)
+ }
+ assembly {
+ let f := shl(6, gt(x, 0xFFFFFFFFFFFFFFFF))
+ x := shr(f, x)
+ msb := or(msb, f)
+ }
+ assembly {
+ let f := shl(5, gt(x, 0xFFFFFFFF))
+ x := shr(f, x)
+ msb := or(msb, f)
+ }
+ assembly {
+ let f := shl(4, gt(x, 0xFFFF))
+ x := shr(f, x)
+ msb := or(msb, f)
+ }
+ assembly {
+ let f := shl(3, gt(x, 0xFF))
+ x := shr(f, x)
+ msb := or(msb, f)
+ }
+ assembly {
+ let f := shl(2, gt(x, 0xF))
+ x := shr(f, x)
+ msb := or(msb, f)
+ }
+ assembly {
+ let f := shl(1, gt(x, 0x3))
+ x := shr(f, x)
+ msb := or(msb, f)
+ }
+ assembly {
+ let f := gt(x, 0x1)
+ msb := or(msb, f)
+ }
+ }
+}
+```
diff --git a/basic_knowledge/boilerplates/1_gm_world.sol b/basic_knowledge/boilerplates/1_gm_world.sol
new file mode 100644
index 0000000..e6986fc
--- /dev/null
+++ b/basic_knowledge/boilerplates/1_gm_world.sol
@@ -0,0 +1,28 @@
+pragma solidity ^0.8.10;
+
+// Defines a contract named `GmWorld`.
+// A contract is a collection of functions and data (its state).
+// Once deployed, a contract resides at a specific address on the Ethereum blockchain.
+contract GmWorld {
+
+ // Declares a state variable `happiness` of type `string`.
+ // State variables are variables whose values are permanently stored in contract storage.
+ // The keyword `public` makes variables accessible from outside a contract
+ // and creates a function that other contracts or clients can call to access the value.
+ string public happiness;
+
+ // Similar to many class-based object-oriented languages, a constructor is
+ // a special function that is only executed upon contract creation.
+ // Constructors are used to initialize the contract's data.
+ constructor(string memory warmGun) public {
+ // Accepts a string argument `warmGun` and sets the value
+ // into the contract's `happiness` storage variable).
+ happiness = warmGun;
+ }
+
+ // A public function that accepts a string argument
+ // and updates the `happiness` storage variable.
+ function update(string memory bobaTea) public {
+ happiness = bobaTea;
+ }
+}
diff --git a/boilerplates/learning/token.sol b/basic_knowledge/boilerplates/2_token.sol
similarity index 100%
rename from boilerplates/learning/token.sol
rename to basic_knowledge/boilerplates/2_token.sol
diff --git a/basic_knowledge/boilerplates/3_wallet.sol b/basic_knowledge/boilerplates/3_wallet.sol
new file mode 100644
index 0000000..97e56b2
--- /dev/null
+++ b/basic_knowledge/boilerplates/3_wallet.sol
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.17;
+
+// An example of a basic wallet.
+// Anyone can send ETH and only the owner can withdraw.
+
+contract EtherWallet {
+ address payable public owner;
+
+ constructor() {
+ owner = payable(msg.sender);
+ }
+
+ receive() external payable {}
+
+ function withdraw(uint _amount) external {
+ require(msg.sender == owner, "caller is not owner");
+ payable(msg.sender).transfer(_amount);
+ }
+
+ function getBalance() external view returns (uint) {
+ return address(this).balance;
+ }
+}
diff --git a/basic_knowledge/boilerplates/4_interable_mapping.sol b/basic_knowledge/boilerplates/4_interable_mapping.sol
new file mode 100644
index 0000000..8fd9250
--- /dev/null
+++ b/basic_knowledge/boilerplates/4_interable_mapping.sol
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.17;
+
+// You cannot iterate through a mapping.
+// So here is an example of how to create an iterable mapping.
+
+
+
+library IterableMapping {
+ // Iterable mapping from address to uint;
+ struct Map {
+ address[] keys;
+ mapping(address => uint) values;
+ mapping(address => uint) indexOf;
+ mapping(address => bool) inserted;
+ }
+
+ function get(Map storage map, address key) public view returns (uint) {
+ return map.values[key];
+ }
+
+ function getKeyAtIndex(Map storage map, uint index) public view returns (address) {
+ return map.keys[index];
+ }
+
+ function size(Map storage map) public view returns (uint) {
+ return map.keys.length;
+ }
+
+ function set(Map storage map, address key, uint val) public {
+ if (map.inserted[key]) {
+ map.values[key] = val;
+ } else {
+ map.inserted[key] = true;
+ map.values[key] = val;
+ map.indexOf[key] = map.keys.length;
+ map.keys.push(key);
+ }
+ }
+
+ function remove(Map storage map, address key) public {
+ if (!map.inserted[key]) {
+ return;
+ }
+
+ delete map.inserted[key];
+ delete map.values[key];
+
+ uint index = map.indexOf[key];
+ address lastKey = map.keys[map.keys.length - 1];
+
+ map.indexOf[lastKey] = index;
+ delete map.indexOf[key];
+
+ map.keys[index] = lastKey;
+ map.keys.pop();
+ }
+}
+
+contract TestIterableMap {
+ using IterableMapping for IterableMapping.Map;
+
+ IterableMapping.Map private map;
+
+ function testIterableMap() public {
+ map.set(address(0), 0);
+ map.set(address(1), 100);
+ map.set(address(2), 200); // insert
+ map.set(address(2), 200); // update
+ map.set(address(3), 300);
+
+ for (uint i = 0; i < map.size(); i++) {
+ address key = map.getKeyAtIndex(i);
+
+ assert(map.get(key) == i * 100);
+ }
+
+ map.remove(address(1));
+
+ // keys = [address(0), address(3), address(2)]
+ assert(map.size() == 3);
+ assert(map.getKeyAtIndex(0) == address(0));
+ assert(map.getKeyAtIndex(1) == address(3));
+ assert(map.getKeyAtIndex(2) == address(2));
+ }
+}
diff --git a/basic_knowledge/boilerplates/5_erc20_interface.sol b/basic_knowledge/boilerplates/5_erc20_interface.sol
new file mode 100644
index 0000000..2b30c20
--- /dev/null
+++ b/basic_knowledge/boilerplates/5_erc20_interface.sol
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.17;
+
+// ERC20 tokens provide functionalities to
+// - transfer tokens
+// - allow others to transfer tokens on behalf of the token holder
+
+
+// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0/contracts/token/ERC20/IERC20.sol
+interface IERC20 {
+ function totalSupply() external view returns (uint);
+
+ function balanceOf(address account) external view returns (uint);
+
+ function transfer(address recipient, uint amount) external returns (bool);
+
+ function allowance(address owner, address spender) external view returns (uint);
+
+ function approve(address spender, uint amount) external returns (bool);
+
+ function transferFrom(
+ address sender,
+ address recipient,
+ uint amount
+ ) external returns (bool);
+
+ event Transfer(address indexed from, address indexed to, uint value);
+ event Approval(address indexed owner, address indexed spender, uint value);
+}
diff --git a/basic_knowledge/boilerplates/6_erc721_interface.sol b/basic_knowledge/boilerplates/6_erc721_interface.sol
new file mode 100644
index 0000000..e59a71e
--- /dev/null
+++ b/basic_knowledge/boilerplates/6_erc721_interface.sol
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.17;
+
+interface IERC165 {
+ function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+interface IERC721 is IERC165 {
+ function balanceOf(address owner) external view returns (uint balance);
+
+ function ownerOf(uint tokenId) external view returns (address owner);
+
+ function safeTransferFrom(address from, address to, uint tokenId) external;
+
+ function transferFrom(address from, address to, uint tokenId) external;
+
+ function approve(address to, uint tokenId) external;
+
+ function getApproved(uint tokenId) external view returns (address operator);
+
+ function setApprovalForAll(address operator, bool _approved) external;
+
+ function isApprovedForAll(
+ address owner,
+ address operator
+ ) external view returns (bool);
+}
+
+interface IERC721Receiver {
+ function onERC721Received(
+ address operator,
+ address from,
+ uint tokenId,
+ bytes calldata data
+ ) external returns (bytes4);
+}
+
+contract ERC721 is IERC721 {
+ event Transfer(address indexed from, address indexed to, uint indexed id);
+ event Approval(address indexed owner, address indexed spender, uint indexed id);
+ event ApprovalForAll(
+ address indexed owner,
+ address indexed operator,
+ bool approved
+ );
+
+ // Mapping from token ID to owner address
+ mapping(uint => address) internal _ownerOf;
+
+ // Mapping owner address to token count
+ mapping(address => uint) internal _balanceOf;
+
+ // Mapping from token ID to approved address
+ mapping(uint => address) internal _approvals;
+
+ // Mapping from owner to operator approvals
+ mapping(address => mapping(address => bool)) public isApprovedForAll;
+
+ function supportsInterface(bytes4 interfaceId) external pure returns (bool) {
+ return
+ interfaceId == type(IERC721).interfaceId ||
+ interfaceId == type(IERC165).interfaceId;
+ }
+
+ function ownerOf(uint id) external view returns (address owner) {
+ owner = _ownerOf[id];
+ require(owner != address(0), "token doesn't exist");
+ }
+
+ function balanceOf(address owner) external view returns (uint) {
+ require(owner != address(0), "owner = zero address");
+ return _balanceOf[owner];
+ }
+
+ function setApprovalForAll(address operator, bool approved) external {
+ isApprovedForAll[msg.sender][operator] = approved;
+ emit ApprovalForAll(msg.sender, operator, approved);
+ }
+
+ function approve(address spender, uint id) external {
+ address owner = _ownerOf[id];
+ require(
+ msg.sender == owner || isApprovedForAll[owner][msg.sender],
+ "not authorized"
+ );
+
+ _approvals[id] = spender;
+
+ emit Approval(owner, spender, id);
+ }
+
+ function getApproved(uint id) external view returns (address) {
+ require(_ownerOf[id] != address(0), "token doesn't exist");
+ return _approvals[id];
+ }
+
+ function _isApprovedOrOwner(
+ address owner,
+ address spender,
+ uint id
+ ) internal view returns (bool) {
+ return (spender == owner ||
+ isApprovedForAll[owner][spender] ||
+ spender == _approvals[id]);
+ }
+
+ function transferFrom(address from, address to, uint id) public {
+ require(from == _ownerOf[id], "from != owner");
+ require(to != address(0), "transfer to zero address");
+
+ require(_isApprovedOrOwner(from, msg.sender, id), "not authorized");
+
+ _balanceOf[from]--;
+ _balanceOf[to]++;
+ _ownerOf[id] = to;
+
+ delete _approvals[id];
+
+ emit Transfer(from, to, id);
+ }
+
+ function safeTransferFrom(address from, address to, uint id) external {
+ transferFrom(from, to, id);
+
+ require(
+ to.code.length == 0 ||
+ IERC721Receiver(to).onERC721Received(msg.sender, from, id, "") ==
+ IERC721Receiver.onERC721Received.selector,
+ "unsafe recipient"
+ );
+ }
+
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint id,
+ bytes calldata data
+ ) external {
+ transferFrom(from, to, id);
+
+ require(
+ to.code.length == 0 ||
+ IERC721Receiver(to).onERC721Received(msg.sender, from, id, data) ==
+ IERC721Receiver.onERC721Received.selector,
+ "unsafe recipient"
+ );
+ }
+
+ function _mint(address to, uint id) internal {
+ require(to != address(0), "mint to zero address");
+ require(_ownerOf[id] == address(0), "already minted");
+
+ _balanceOf[to]++;
+ _ownerOf[id] = to;
+
+ emit Transfer(address(0), to, id);
+ }
+
+ function _burn(uint id) internal {
+ address owner = _ownerOf[id];
+ require(owner != address(0), "not minted");
+
+ _balanceOf[owner] -= 1;
+
+ delete _ownerOf[id];
+ delete _approvals[id];
+
+ emit Transfer(owner, address(0), id);
+ }
+}
+
+contract MyNFT is ERC721 {
+ function mint(address to, uint id) external {
+ _mint(to, id);
+ }
+
+ function burn(uint id) external {
+ require(msg.sender == _ownerOf[id], "not owner");
+ _burn(id);
+ }
+}
diff --git a/basic_knowledge/boilerplates/7_erc1155.sol b/basic_knowledge/boilerplates/7_erc1155.sol
new file mode 100644
index 0000000..0ef72ce
--- /dev/null
+++ b/basic_knowledge/boilerplates/7_erc1155.sol
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.17;
+
+interface IERC1155 {
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint256 id,
+ uint256 value,
+ bytes calldata data
+ ) external;
+
+ function safeBatchTransferFrom(
+ address from,
+ address to,
+ uint256[] calldata ids,
+ uint256[] calldata values,
+ bytes calldata data
+ ) external;
+
+ function balanceOf(address owner, uint256 id) external view returns (uint256);
+
+ function balanceOfBatch(
+ address[] calldata owners,
+ uint256[] calldata ids
+ ) external view returns (uint256[] memory);
+
+ function setApprovalForAll(address operator, bool approved) external;
+
+ function isApprovedForAll(
+ address owner,
+ address operator
+ ) external view returns (bool);
+}
+
+interface IERC1155TokenReceiver {
+ function onERC1155Received(
+ address operator,
+ address from,
+ uint256 id,
+ uint256 value,
+ bytes calldata data
+ ) external returns (bytes4);
+
+ function onERC1155BatchReceived(
+ address operator,
+ address from,
+ uint256[] calldata ids,
+ uint256[] calldata values,
+ bytes calldata data
+ ) external returns (bytes4);
+}
+
+contract ERC1155 is IERC1155 {
+ event TransferSingle(
+ address indexed operator,
+ address indexed from,
+ address indexed to,
+ uint256 id,
+ uint256 value
+ );
+ event TransferBatch(
+ address indexed operator,
+ address indexed from,
+ address indexed to,
+ uint256[] ids,
+ uint256[] values
+ );
+ event ApprovalForAll(
+ address indexed owner,
+ address indexed operator,
+ bool approved
+ );
+ event URI(string value, uint256 indexed id);
+
+ // owner => id => balance
+ mapping(address => mapping(uint256 => uint256)) public balanceOf;
+ // owner => operator => approved
+ mapping(address => mapping(address => bool)) public isApprovedForAll;
+
+ function balanceOfBatch(
+ address[] calldata owners,
+ uint256[] calldata ids
+ ) external view returns (uint256[] memory balances) {
+ require(owners.length == ids.length, "owners length != ids length");
+
+ balances = new uint[](owners.length);
+
+ unchecked {
+ for (uint256 i = 0; i < owners.length; i++) {
+ balances[i] = balanceOf[owners[i]][ids[i]];
+ }
+ }
+ }
+
+ function setApprovalForAll(address operator, bool approved) external {
+ isApprovedForAll[msg.sender][operator] = approved;
+ emit ApprovalForAll(msg.sender, operator, approved);
+ }
+
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint256 id,
+ uint256 value,
+ bytes calldata data
+ ) external {
+ require(
+ msg.sender == from || isApprovedForAll[from][msg.sender],
+ "not approved"
+ );
+ require(to != address(0), "to = 0 address");
+
+ balanceOf[from][id] -= value;
+ balanceOf[to][id] += value;
+
+ emit TransferSingle(msg.sender, from, to, id, value);
+
+ if (to.code.length > 0) {
+ require(
+ IERC1155TokenReceiver(to).onERC1155Received(
+ msg.sender,
+ from,
+ id,
+ value,
+ data
+ ) == IERC1155TokenReceiver.onERC1155Received.selector,
+ "unsafe transfer"
+ );
+ }
+ }
+
+ function safeBatchTransferFrom(
+ address from,
+ address to,
+ uint256[] calldata ids,
+ uint256[] calldata values,
+ bytes calldata data
+ ) external {
+ require(
+ msg.sender == from || isApprovedForAll[from][msg.sender],
+ "not approved"
+ );
+ require(to != address(0), "to = 0 address");
+ require(ids.length == values.length, "ids length != values length");
+
+ for (uint256 i = 0; i < ids.length; i++) {
+ balanceOf[from][ids[i]] -= values[i];
+ balanceOf[to][ids[i]] += values[i];
+ }
+
+ emit TransferBatch(msg.sender, from, to, ids, values);
+
+ if (to.code.length > 0) {
+ require(
+ IERC1155TokenReceiver(to).onERC1155BatchReceived(
+ msg.sender,
+ from,
+ ids,
+ values,
+ data
+ ) == IERC1155TokenReceiver.onERC1155BatchReceived.selector,
+ "unsafe transfer"
+ );
+ }
+ }
+
+ // ERC165
+ function supportsInterface(bytes4 interfaceId) external view returns (bool) {
+ return
+ interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
+ interfaceId == 0xd9b67a26 || // ERC165 Interface ID for ERC1155
+ interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI
+ }
+
+ // ERC1155 Metadata URI
+ function uri(uint256 id) public view virtual returns (string memory) {}
+
+ // Internal functions
+ function _mint(address to, uint256 id, uint256 value, bytes memory data) internal {
+ require(to != address(0), "to = 0 address");
+
+ balanceOf[to][id] += value;
+
+ emit TransferSingle(msg.sender, address(0), to, id, value);
+
+ if (to.code.length > 0) {
+ require(
+ IERC1155TokenReceiver(to).onERC1155Received(
+ msg.sender,
+ address(0),
+ id,
+ value,
+ data
+ ) == IERC1155TokenReceiver.onERC1155Received.selector,
+ "unsafe transfer"
+ );
+ }
+ }
+
+ function _batchMint(
+ address to,
+ uint256[] calldata ids,
+ uint256[] calldata values,
+ bytes calldata data
+ ) internal {
+ require(to != address(0), "to = 0 address");
+ require(ids.length == values.length, "ids length != values length");
+
+ for (uint256 i = 0; i < ids.length; i++) {
+ balanceOf[to][ids[i]] += values[i];
+ }
+
+ emit TransferBatch(msg.sender, address(0), to, ids, values);
+
+ if (to.code.length > 0) {
+ require(
+ IERC1155TokenReceiver(to).onERC1155BatchReceived(
+ msg.sender,
+ address(0),
+ ids,
+ values,
+ data
+ ) == IERC1155TokenReceiver.onERC1155BatchReceived.selector,
+ "unsafe transfer"
+ );
+ }
+ }
+
+ function _burn(address from, uint256 id, uint256 value) internal {
+ require(from != address(0), "from = 0 address");
+ balanceOf[from][id] -= value;
+ emit TransferSingle(msg.sender, from, address(0), id, value);
+ }
+
+ function _batchBurn(
+ address from,
+ uint256[] calldata ids,
+ uint256[] calldata values
+ ) internal {
+ require(from != address(0), "from = 0 address");
+ require(ids.length == values.length, "ids length != values length");
+
+ for (uint256 i = 0; i < ids.length; i++) {
+ balanceOf[from][ids[i]] -= values[i];
+ }
+
+ emit TransferBatch(msg.sender, from, address(0), ids, values);
+ }
+}
+
+contract MyMultiToken is ERC1155 {
+ function mint(uint256 id, uint256 value, bytes memory data) external {
+ _mint(msg.sender, id, value, data);
+ }
+
+ function batchMint(
+ uint256[] calldata ids,
+ uint256[] calldata values,
+ bytes calldata data
+ ) external {
+ _batchMint(msg.sender, ids, values, data);
+ }
+
+ function burn(uint256 id, uint256 value) external {
+ _burn(msg.sender, id, value);
+ }
+
+ function batchBurn(uint256[] calldata ids, uint256[] calldata values) external {
+ _batchBurn(msg.sender, ids, values);
+ }
+}
diff --git a/basic_knowledge/boilerplates/8_bytecode_contract.sol b/basic_knowledge/boilerplates/8_bytecode_contract.sol
new file mode 100644
index 0000000..b1f0e7b
--- /dev/null
+++ b/basic_knowledge/boilerplates/8_bytecode_contract.sol
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.17;
+
+// simple example of contract written in bytecode
+
+contract Factory {
+ event Log(address addr);
+
+ // Deploys a contract that always returns 42
+ function deploy() external {
+ bytes memory bytecode = hex"69602a60005260206000f3600052600a6016f3";
+ address addr;
+ assembly {
+ // create(value, offset, size)
+ addr := create(0, add(bytecode, 0x20), 0x13)
+ }
+ require(addr != address(0));
+
+ emit Log(addr);
+ }
+}
+
+interface IContract {
+ function getMeaningOfLife() external view returns (uint);
+}
+
+// https://www.evm.codes/playground
+/*
+Run time code - return 42
+602a60005260206000f3
+
+// Store 42 to memory
+mstore(p, v) - store v at memory p to p + 32
+
+PUSH1 0x2a
+PUSH1 0
+MSTORE
+
+// Return 32 bytes from memory
+return(p, s) - end execution and return data from memory p to p + s
+
+PUSH1 0x20
+PUSH1 0
+RETURN
+
+Creation code - return runtime code
+69602a60005260206000f3600052600a6016f3
+
+// Store run time code to memory
+PUSH10 0X602a60005260206000f3
+PUSH1 0
+MSTORE
+
+// Return 10 bytes from memory starting at offset 22
+PUSH1 0x0a
+PUSH1 0x16
+RETURN
+*/
diff --git a/basic_knowledge/boilerplates/README.md b/basic_knowledge/boilerplates/README.md
new file mode 100644
index 0000000..6b90df9
--- /dev/null
+++ b/basic_knowledge/boilerplates/README.md
@@ -0,0 +1,12 @@
+## contracts boilerplates and examples to learn solidity
+
+
+
+* **[gm_world.sol](1_gm_world.sol)**
+* **[token.sol](2_token.sol)**
+* **[wallet.sol](3_wallet.sol)**
+* **[interable_mapping.sol](4_interable_mapping.sol)**
+* **[erc20_interface.sol](5_erc20_interface.sol)**
+* **[erc721_interface.sol](6_erc721_interface.sol)**
+* **[erc1155.sol](7_erc1155.sol)**
+* **[bytecode_contract.sol](8_bytecode_contract.sol)**
diff --git a/basic_knowledge/token_standards/README.md b/basic_knowledge/token_standards/README.md
new file mode 100644
index 0000000..c9884d3
--- /dev/null
+++ b/basic_knowledge/token_standards/README.md
@@ -0,0 +1,26 @@
+## ethereum token standards
+
+
+
+### tl; dr
+
+
+
+* EIP stands for **ethereum improvement proposals**.
+* ERC stands for **ethereum request for comments** (technical documents written by ethereum developers for ethereum community).
+* each such document contains a set of rules required to implement tokens for the ethereum ecosystem.
+
+
+
+---
+
+### in this dir
+
+
+
+* **[ERC20](erc20.md)**
+* **[ERC777](erc777.md)**
+* **[ERC721](erc721.md)**
+
+
+
diff --git a/basic_knowledge/token_standards/erc20.md b/basic_knowledge/token_standards/erc20.md
new file mode 100644
index 0000000..05c6129
--- /dev/null
+++ b/basic_knowledge/token_standards/erc20.md
@@ -0,0 +1,67 @@
+## ERC20
+
+
+
+* defines a common interface for contracts implementing this token, such that any compatible token can be accessed and used in the same way.
+* a transaction sending ether to an address changes the state of an address. a transaction transferring a token to an address only changes the state of the token contract, not the state of the recipient address.
+* one of the main reasons for the success of EIP-20 tokens is in the interplay between `approve` and `transferFrom`, which allows for tokens to not
+only be transferred between externally owned accounts (EOA).
+ - but to be used in other contracts under application specific conditions by abstracting away `msg.sender` as the mechanism for token access control.
+* a limiting factor lies from the fact that the EIP-20 `approve` function is defined in terms of `msg.sender`.
+ - this means that userās initial action involving EIP-20 tokens must be performed by an EOA.
+ - if the user needs to interact with a smart contract, then they need to make 2 transactions (`approve` and the smart contract internal call `transferFrom`), with gas costs.
+
+
+
+
+---
+
+### ERC20-compliant token contract
+
+
+
+* `totalSupply`: Returns the total units of this token that currently exist. ERC20 tokens can have a fixed or a variable supply.
+* `balanceOf`: Given an address, returns the token balance of that address.
+* `transfer`: Given an address and amount, transfers that amount of tokens to that address, from the balance of the address that executed the transfer.
+* `transferFrom`: Given a sender, recipient, and amount, transfers tokens from one account to another. Used in combination with approve.
+* `approve`: given a recipient address and amount, authorizes that address to execute several transfers up to that amount, from the account that issued the approval.
+* `allowance`: given an owner address and a spender address, returns the remaining amount that the spender is approved to withdraw from the owner.
+* `Transfer`: event triggered upon a successful transfer (call to transfer or transferFrom) (even for zero-value transfers).
+* `Approval`: event logged upon a successful call to approve.
+
+
+
+---
+
+### ERC20 optional functions
+
+
+
+* in addition to the required functions listed in the previous section, the following optional functions are also defined by the standard:
+ - `name`: returns the human-readable name (e.g., "US Dollars") of the token.
+ - `symbol`: returns a human-readable symbol (e.g., "USD") for the token.
+ - `decimals`: returns the number of decimals used to divide token amounts. For example, if decimals is 2, then the token amount is divided by 100 to get its user representation.
+
+
+
+---
+
+### the ERC20 interface
+
+
+
+```
+contract ERC20 {
+ function totalSupply() constant returns (uint theTotalSupply);
+ function balanceOf(address _owner) constant returns (uint balance);
+ function transfer(address _to, uint _value) returns (bool success);
+ function transferFrom(address _from, address _to, uint _value) returns
+ (bool success);
+ function approve(address _spender, uint _value) returns (bool success);
+ function allowance(address _owner, address _spender) constant returns
+ (uint remaining);
+ event Transfer(address indexed _from, address indexed _to, uint _value);
+ event Approval(address indexed _owner, address indexed _spender, uint _value);
+}
+```
+
diff --git a/token_standards/erc721.md b/basic_knowledge/token_standards/erc721.md
similarity index 72%
rename from token_standards/erc721.md
rename to basic_knowledge/token_standards/erc721.md
index 4fef101..93f23eb 100644
--- a/token_standards/erc721.md
+++ b/basic_knowledge/token_standards/erc721.md
@@ -3,7 +3,7 @@
-To see the difference between ERC20 and ERC721, look at the internal data structure used in ERC721:
+* to see the difference between ERC20 and ERC721, look at the internal data structure used in ERC721:
```
@@ -12,14 +12,15 @@ mapping (uint256 => address) private deedOwner;
-Whereas ERC20 tracks the balances that belong to each owner, with the owner being the primary key of the mapping,
-ERC721 tracks each deed ID and who owns it, with the deed ID being the primary key of the mapping.
+* whereas ERC20 tracks the balances that belong to each owner, with the owner being the primary key of the mapping, ERC721 tracks each deed ID and who owns it, with the deed ID being the primary key of the mapping.
+---
-### The ERC721 contract interface specification
+### the ERC721 contract interface specification
+
```
interface ERC721 /* is ERC165 */ {
diff --git a/token_standards/erc777.md b/basic_knowledge/token_standards/erc777.md
similarity index 99%
rename from token_standards/erc777.md
rename to basic_knowledge/token_standards/erc777.md
index eac66ff..3257da9 100644
--- a/token_standards/erc777.md
+++ b/basic_knowledge/token_standards/erc777.md
@@ -3,23 +3,14 @@
* an ERC20-compatible interface
-
* transfer tokens using a send function, similar to ether transfers
-
* compatible with ERC820 for token contract registration
-
* allow contracts and addresses to control which tokens they send through a tokensToSend function that is called prior to sending
-
* enable contracts and addresses to be notified of the tokens' receipt by calling a tokensReceived function in the recipient, and to reduce the probability of tokens being locked into contracts by requiring contracts to provide a tokensReceived function
-
* allow existing contracts to use proxy contracts for the `tokensToSend and `tokensReceived` functions
-
* operate in the same way whether sending to a contract or an EOA
-
* provide specific events for the minting and burning of tokens
-
* enable operators (trusted third parties, intended to be verified contracts) to move tokens on behalf of a token holder
-
* provide metadata on token transfer transactions in userData and operatorData fields
diff --git a/basic_knowledge/workspace/README.md b/basic_knowledge/workspace/README.md
new file mode 100644
index 0000000..83bc6fa
--- /dev/null
+++ b/basic_knowledge/workspace/README.md
@@ -0,0 +1,8 @@
+## workspaces
+
+
+
+* **[i use foundry](foundry.md)**
+* **[notes on using remix](remix.md)**
+* **[a simple intro to hardhat with a `erc721` token](hardhat/)**
+* **[old stuff: truffle](https://trufflesuite.com/)**
diff --git a/basic_knowledge/workspace/foundry.md b/basic_knowledge/workspace/foundry.md
new file mode 100644
index 0000000..54d12a3
--- /dev/null
+++ b/basic_knowledge/workspace/foundry.md
@@ -0,0 +1,31 @@
+## foundry and tests in solidity
+
+
+
+
+### tl; dr
+
+
+
+
+* **[foundry](https://book.getfoundry.sh/forge/differential-ffi-testing)** is a set of tools for evm-based smart contract development and tests, written in rust.
+
+
+
+
+
+---
+
+### resources
+
+
+
+* **[ethernaut solutions systematically on foundry](https://github.com/go-outside-labs/ethernaut-foundry-detailed-solutions-sol)**
+* **[go-outside-labs experiments on foundry](https://github.com/go-outside-labs/blockchain-science-rs#experiments-with-foundry)**
+* **[how to test smart contracts](https://betterprogramming.pub/how-to-test-ethereum-smart-contracts-35abc8fa199d)**
+* **[how to mock solidity contracts](https://ethereum.org/en/developers/tutorials/how-to-mock-solidity-contracts-for-testing/)**
+* **[in-depth guide to testing ethereum smart contracts](https://iamdefinitelyahuman.medium.com/an-in-depth-guide-to-testing-ethereum-smart-contracts-2e41b2770297)**
+
+
+
+
diff --git a/boilerplates/solidity_101/.env_sample b/basic_knowledge/workspace/hardhat/.env_sample
similarity index 100%
rename from boilerplates/solidity_101/.env_sample
rename to basic_knowledge/workspace/hardhat/.env_sample
diff --git a/boilerplates/solidity_101/README.md b/basic_knowledge/workspace/hardhat/README.md
similarity index 69%
rename from boilerplates/solidity_101/README.md
rename to basic_knowledge/workspace/hardhat/README.md
index 51b23f9..75986e2 100644
--- a/boilerplates/solidity_101/README.md
+++ b/basic_knowledge/workspace/hardhat/README.md
@@ -1,20 +1,25 @@
## get started with hardhat + erc721
+
-1. Compile contract:
+1. compile contract:
```
npx hardhat compile
```
+
-2. Deploy contract:
+
+2. deploy contract:
```
npx hardhat run scripts/deploy-contract.js --network rinkeby
```
-3. Mint NFT:
+
+
+3. mint NFT:
```
node scripts/mint-nft.js
-```
\ No newline at end of file
+```
diff --git a/boilerplates/solidity_101/contracts/MiaNFT.sol b/basic_knowledge/workspace/hardhat/contracts/MiaNFT.sol
similarity index 99%
rename from boilerplates/solidity_101/contracts/MiaNFT.sol
rename to basic_knowledge/workspace/hardhat/contracts/MiaNFT.sol
index 1bb8d51..d0d694e 100644
--- a/boilerplates/solidity_101/contracts/MiaNFT.sol
+++ b/basic_knowledge/workspace/hardhat/contracts/MiaNFT.sol
@@ -25,4 +25,4 @@ contract MiaNFT is ERC721, Ownable {
return newItemId;
}
-}
\ No newline at end of file
+}
diff --git a/boilerplates/solidity_101/hardhat.config.js b/basic_knowledge/workspace/hardhat/hardhat.config.js
similarity index 100%
rename from boilerplates/solidity_101/hardhat.config.js
rename to basic_knowledge/workspace/hardhat/hardhat.config.js
diff --git a/boilerplates/solidity_101/package.json b/basic_knowledge/workspace/hardhat/package.json
similarity index 93%
rename from boilerplates/solidity_101/package.json
rename to basic_knowledge/workspace/hardhat/package.json
index a863d5e..193fb1f 100644
--- a/boilerplates/solidity_101/package.json
+++ b/basic_knowledge/workspace/hardhat/package.json
@@ -5,7 +5,7 @@
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
- "author": "Mia von Steinkirch",
+ "author": "Mia Stein",
"license": "MIT",
"devDependencies": {
"@nomiclabs/hardhat-ethers": "^2.0.2",
diff --git a/boilerplates/solidity_101/scripts/deploy-contract.js b/basic_knowledge/workspace/hardhat/scripts/deploy-contract.js
similarity index 100%
rename from boilerplates/solidity_101/scripts/deploy-contract.js
rename to basic_knowledge/workspace/hardhat/scripts/deploy-contract.js
diff --git a/boilerplates/solidity_101/scripts/mint-nft.js b/basic_knowledge/workspace/hardhat/scripts/mint-nft.js
similarity index 100%
rename from boilerplates/solidity_101/scripts/mint-nft.js
rename to basic_knowledge/workspace/hardhat/scripts/mint-nft.js
diff --git a/basic_knowledge/workspace/remix.md b/basic_knowledge/workspace/remix.md
new file mode 100644
index 0000000..8902f3e
--- /dev/null
+++ b/basic_knowledge/workspace/remix.md
@@ -0,0 +1,68 @@
+## remix IDE
+
+
+
+* remix IDE is an open source web3 application and it's used for the entire journey of smart contract development.
+
+
+
+
+
+
+
+
+* everything in Remix is a plugin. the plugin mamanger is the place to load functionalities and create your own plugins.
+* by default, Remix stores files in workspaces, which are folders in the browser's local storage.
+* you can publish all files from current workspace to a gist, using the gist API.
+
+
+
+
+#### compiler (Solidity)
+
+* you can compile (and deploy) contracts with versions of Solidity older than 0.4.12. however, the older compilers used a legacy AST.
+* the "fork selection" dropdown list allows to compile code against a specific ehtereum hard fork.
+
+
+
+
+#### optimization
+
+* the optimizer tries to simplify complicated expressions, which reduces both code size and execution cost. It can reduce gas needed for contract deployment as well as for external calls made to the contract.
+
+
+
+
+#### environment
+
+* `JavaScript VM`: All transactions will be executed in a sandbox blockchain in the browser.
+* `Injected Provider`: Metamaask is an example of a profiver that inject web3.
+* `Web3 Provider`: Remix will connect to a remote node (you need to provide the URL to the selected provider: geth, parity or any ethereum client)
+
+
+
+
+#### setup
+
+* gas Limit: sets the amount of `ETH`, `WEI`, `GWEI` that is sent to ta contract or a payable function.
+* deploy: sends a transaction that deplpys the selected contract.
+* `atAdress`: used to access a contract whtat has already been deployed (does not cost gas).
+* to interact with a contract using the ABI, create a new file in remix, with extension `.abi`.
+* the Recorder is a tool used to save a bunch of transactions in a `json` file and rerun them later either in the same environment or in another.
+* the Debugger shows the contract's state while stepping through a transaction.
+* using generated sources will make it easier to audit your contracts.
+* dtatic code analysis can be done by a plugin, so that you can examine the code for security vulnerabilities, bad development practices, etc.
+* hardhat integration can be done with `hardhat.config.js` (Hardhat websocket listener should run at `65522`). hardhat provider is a plugin for Rrmix IDE.
+
+
+
+
+#### generate artifacts
+
+* when a compilation for a Solidity file succeeds, remix creates three `json` files for each compiled contract, that can be seen in the `File Explorers plugin`:
+
+1. `artifacts/.json`: contains links to libraries, the bytecode, gas estimation, the ABI.
+2. `articfacts/.json`: contains the metadata from the output of Solidity compilation.
+3. `artifcats/build-info/.json`: contains info about `solc` compiler version, compiler input and output.
+
+
diff --git a/boilerplates/README.md b/boilerplates/README.md
deleted file mode 100644
index 78f91c9..0000000
--- a/boilerplates/README.md
+++ /dev/null
@@ -1,8 +0,0 @@
-## boilerplates
-
-
-
-* [learning](learning)
-* [solidity 101](solidity_101)
-
-
diff --git a/boilerplates/learning/hello-world.sol b/boilerplates/learning/hello-world.sol
deleted file mode 100644
index 24bd164..0000000
--- a/boilerplates/learning/hello-world.sol
+++ /dev/null
@@ -1,32 +0,0 @@
-// Specifies the version of Solidity, using semantic versioning.
-// Learn more: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma
-pragma solidity ^0.5.10;
-
-// Defines a contract named `HelloWorld`.
-// A contract is a collection of functions and data (its state).
-// Once deployed, a contract resides at a specific address on the Ethereum blockchain.
-// Learn more: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html
-contract HelloWorld {
-
- // Declares a state variable `message` of type `string`.
- // State variables are variables whose values are permanently stored in contract storage.
- // The keyword `public` makes variables accessible from outside a contract
- // and creates a function that other contracts or clients can call to access the value.
- string public message;
-
- // Similar to many class-based object-oriented languages, a constructor is
- // a special function that is only executed upon contract creation.
- // Constructors are used to initialize the contract's data.
- // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors
- constructor(string memory initMessage) public {
- // Accepts a string argument `initMessage` and sets the value
- // into the contract's `message` storage variable).
- message = initMessage;
- }
-
- // A public function that accepts a string argument
- // and updates the `message` storage variable.
- function update(string memory newMessage) public {
- message = newMessage;
- }
-}
diff --git a/foundry/README.md b/foundry/README.md
deleted file mode 100644
index 8210d34..0000000
--- a/foundry/README.md
+++ /dev/null
@@ -1,30 +0,0 @@
-## foundry and tests in solidity
-
-
-
-
-### tl; dr
-
-
-
-
-* foundry is a set of tools for ethereum applications development, including tests in solidity
-
-
-
-
-
-
----
-
-### resources
-
-
-
-* [how to mock solidity contracts](https://ethereum.org/en/developers/tutorials/how-to-mock-solidity-contracts-for-testing/)
-* [truffle smart contract test framework](https://ethereum.org/en/developers/tutorials/how-to-mock-solidity-contracts-for-testing/)
-* [in-depth guide to testing ethereum smart contracts](https://iamdefinitelyahuman.medium.com/an-in-depth-guide-to-testing-ethereum-smart-contracts-2e41b2770297)
-* [how to test smart contracts](https://betterprogramming.pub/how-to-test-ethereum-smart-contracts-35abc8fa199d)
-* [foundry book](https://book.getfoundry.sh/forge/differential-ffi-testing)
-
-
diff --git a/foundry/unit-testing.md b/foundry/unit-testing.md
deleted file mode 100644
index ae88d23..0000000
--- a/foundry/unit-testing.md
+++ /dev/null
@@ -1,91 +0,0 @@
-## basic solidity unity test
-
-
-
-### assert vs. require
-
-* Assert() should only be used to test for internal errors, and to check invariants.
-* Require() should be used to ensure valid conditions are met that cannot be detected until execution time.
-* You may optionally provide a message for require, but not for assert.
-
-
-
-
-
-### functions
-
-
-
-
-functions in a test file to make testing more structural:
-
-* `beforeEach()` - Runs before each test
-* `beforeAll()` - Runs before all tests
-* `afterEach()` - Runs after each test
-* `afterAll()` - Runs after all tests
-
-
-
-a generic unit testing file looks like:
-
-
-```
-pragma solidity >=0.4.22 <0.8.0;
-import "remix_tests.sol"; // this import is automatically injected by Remix.
-import "remix_accounts.sol";
-// Import here the file to test.
-
-// File name has to end with '_test.sol', this file can contain more than one testSuite contracts
-contract testSuite {
-
- /// 'beforeAll' runs before all other tests
- /// More special functions are: 'beforeEach', 'beforeAll', 'afterEach' & 'afterAll'
- function beforeAll() public {
- // Here should instantiate tested contract
- Assert.equal(uint(1), uint(1), "1 should be equal to 1");
- }
-
- function checkSuccess() public {
- // Use 'Assert' to test the contract,
- // See documentation: https://remix-ide.readthedocs.io/en/latest/assert_library.html
- Assert.equal(uint(2), uint(2), "2 should be equal to 2");
- Assert.notEqual(uint(2), uint(3), "2 should not be equal to 3");
- }
-
- function checkSuccess2() public pure returns (bool) {
- // Use the return value (true or false) to test the contract
- return true;
- }
-
- function checkFailure() public {
- Assert.equal(uint(1), uint(2), "1 is not equal to 2");
- }
-
- /// Custom Transaction Context
- /// See more: https://remix-ide.readthedocs.io/en/latest/unittesting.html#customization
- /// #sender: account-1
- /// #value: 100
- function checkSenderAndValue() public payable {
- // account index varies 0-9, value is in wei
- Assert.equal(msg.sender, TestsAccounts.getAccount(1), "Invalid sender");
- Assert.equal(msg.value, 100, "Invalid value");
- }
-}
-```
-
-note that ine can input custom values for `msg.sender` & `msg.value` of transaction using NatSpec comments.
-
-
-
-
----
-
-### resources
-
-
-
-* [Solidity-Coverage](https://github.com/sc-forks/solidity-coverage)
-* [Remix tests](https://github.com/ethereum/remix-project/tree/master/libs/remix-tests)
-* [OpenZeppelin test helpers](https://github.com/OpenZeppelin/openzeppelin-test-helpers)
-* [foundry forge tests](https://github.com/foundry-rs/foundry/tree/master/forge)
-* [etheno](https://github.com/crytic/etheno)
diff --git a/saving_gas/README.md b/saving_gas/README.md
deleted file mode 100644
index 9dd44a6..0000000
--- a/saving_gas/README.md
+++ /dev/null
@@ -1,144 +0,0 @@
-## gas
-
-
-
-### gas costs
-
-
-
-- gas is the cost for on-chain computation and storage. examples:
- - addition costs 3 gas, keccak-256 costs 30 gas + 6 gas for each 256 bits of data being hashed
- - sending a transaction costs 21,000 gas (intrinsic gas)
- - creating a contract cost 32000 gas
-- each **calldata** byte costs gas (gas per byte equal to 0, and 16 gas for the others), the larger the size of the transaction data, the higher the gas fees.
-- each opcode has a [specific fixed cost to be paid upon execution](https://www.evm.codes/?fork=arrowGlacier)
-
-
-
-----
-
-### calculating gas for your code
-
-
-
-* online: [remix](https://remix.ethereum.org/)
-
-
-
-
-----
-
-
-### tricks to save gas
-
-
-
-#### small ones
-
-
-
-- brute force hashes of function names to find those that start 0000, so this can save around 50 gas.
-- if you donāt need a variable anymore, you should delete it using the delete keyword provided by solidity or by setting it to its default value.
-- avoid calls to other contracts.
-- ++i uses 5 gas less than i++.
-
-
-
-
-
-
-
-
-
-
-#### pack variables
-
-The below code is an example of poorĀ code and will consume 3 storage slot:
-
-```
-uint8 numberOne;
-uint256 bigNumber;
-uint8 numberTwo;
-```
-
-A much more efficient way to do this in solidity will be:
-
-```
-uint8 numberOne;
-uint8 numberTwo;
-uint256 bigNumber;
-```
-
-
-
-#### constant vs. immutable variables
-
-Constant values can sometimes be cheaper than immutable values:
-
-- For a constant variable, the expression assigned to it is copied to all the places where it is accessed and also re-evaluated each time, allowing local optimizations.
-- Immutable variables are evaluated once at construction time and their value is copied to all the places in the code where they are accessed. For these values, 32 bytes are reserved, even if they would fit in fewer bytes.
-
-
-#### mappings are cheaper than Arrays
-
-- avoid dynamically sized arrays
-- An array is not stored sequentially in memory but as a mapping.
-- You can pack Arrays but not Mappings.
-- Itās cheaper to use arrays if you are using smaller elements like `uint8` which can be packed together.
-- You canāt get the length of a mapping or parse through all its elements, so depending on your use case, you might be forced to use an Array even though it might cost you more gas.
-
-
-#### use bytes32 rather than string/bytes
-
-- If you can fit your data in 32 bytes, then you should use bytes32 datatype rather than bytes or strings as it is much cheaper in solidity.
-- Any fixed size variable in solidity is cheaper than variable size.
-
-#### modifiers
-
-- For all the public functions, the input parameters are copied to memory automatically, and it costs gas.
-- If your function is only called externally, then you should explicitly mark it as external.
-- External functionās parameters are not copied into memory but are read from `calldata` directly.
-- internal and private are both cheaper than public and external when called from inside the contract in some cases.
-
-
-
-#### no need to initialize variables with default values
-
-- If a variable is not set/initialized, it is assumed to have the default value (0, false, 0x0 etc depending on the data type). If you explicitly initialize it with its default value, you are just wasting gas.
-
-```
-uint256 hello = 0; //bad, expensive
-uint256 world; //good, cheap
-```
-
-
-#### make use of single line swaps
-
-- This is space-efficient:
-
-```
-(hello, world) = (world, hello)
-```
-
-#### negative gas costs
-
-- Deleting a contract (SELFDESTRUCT) is worth a refund of 24,000 gas.
-- Changing a storage address from a nonzero value to zero (SSTORE[x] = 0) is worth a refund of 15,000 gas.
-
-
-
-
----
-
-### resources
-
-
-
-* [truffle contract size](https://github.com/IoBuilders/truffle-contract-size)
-* [foundry book on gas](https://book.getfoundry.sh/forge/gas-reports)
-* [solidity gas optimizations](https://mirror.xyz/haruxe.eth/DW5verFv8KsYOBC0SxqWORYry17kPdeS94JqOVkgxAA)
-* [hardhat on gas optimization](https://medium.com/@thelasthash/%EF%B8%8F-gas-optimization-with-hardhat-1e553eaea311)
-* [resources for gas optimization](https://github.com/kadenzipfel/gas-optimizations)
-* [awesome solidity gas optimization](https://github.com/iskdrews/awesome-solidity-gas-optimization)
-
-
diff --git a/solidity_tldr.md b/solidity_tldr.md
deleted file mode 100644
index b3cae3e..0000000
--- a/solidity_tldr.md
+++ /dev/null
@@ -1,442 +0,0 @@
-
-## solidity tl;dr
-
-
-
-### ethereum contracts
-
-
-
-* until [account abstraction](https://github.com/go-outside-labs/mev-toolkit/tree/main/MEV_by_chains/MEV_on_Ethereum/account_abstraction) becomes a thing, there are two types of accounts, which are identified by an address of **160-bit length** (rightmost 160 bits of the **Keccak hash** of the RLP encoding of the structure with the sender and the nonce), and contain a **balance** (in wei), a **nonce** (number of tx made by the account), a **bytecode** (hash), and **stored data** (keccak hash of the root note od the storage trie). while **external accounts have a private key** and their code and storage are empty, **contract accounts store their bytecode** (and merkle root hash of the entire state tree).
-
-
-
-
-
-
-
-
-
-* the **creation of a contract** is a transaction where the **receiver address is empty** and its **data field contains compiled bytecode** (or calling `CREATE` opcode. the data sent is executed as bytecode, initializing the state variables in storage and determining the body of the contract being created. **contract memory** is a byte array, where data can be stored in 32 bytes (256 bit) or 1 byte (8 bit) chunks, reading in 32 bytes chunks (through `MSTORE`, `MLOAD`, `MSTORE8`).
-
-
-
-
-
-
-
-
-* contracts can call contracts through **message calls** (`CALL` opcode). every call has a **sender**, a **recipient**, a **payload** (data), a **value** (in wei), and some **gas**. a variant is `DELEGATECALL`, where target code is executed within the context of the calling contract, and `msg.sender` and `msg.value` do not change (the contract can dynamically load code - storage - from a different address at runtime - while current address and balance still refer to the calling contract).
-
-
-
-------
-
-### predefined global variables and functions
-
-
-
-* when a contract is executed in the EVM, it has access to a small set of global objects: `block`, `msg`, and `tx` objects. in addition, solidity exposes a number of EVM opcodes as predefined functions:
-
-
-
-
-##### msg
-
-* `msg object`: the transaction that triggered the execution of the contract.
-* `msg.sender`: sender address of the transaction.
-* `msg.value`: ether sent with this call (in wei).
-* `msg.data`: data payload of this call into our contract.
-* `msg.sig`: first four bytes of the data payload, which is the function selector.
-
-
-
-##### tx
-
-* `tx.gasprice`: gas price in the calling transaction.
-* `tx.origin`: address of the originating EOA for this transaction. WARNING: unsafe!
-
-
-
-##### block
-
-* `block.coinbase`: address of the recipient of the current block's fees and block reward.
-* `block.gaslimit`: maximum amount of gas that can be spent across all transactions included in the current block.
-* `block.number`: current block number (blockchain height).
-* `block.timestamp`: timestamp placed in the current block by the miner (number of seconds since the Unix epoch).
-
-
-
-##### address
-
-* `address.balance`: balance of the address, in wei.
-* `address.transfer(__amount__)`: transfers the amount (in wei) to this address, throwing an exception on any error.
-* `address.send(__amount__)`: similar to transfer, only instead of throwing an exception, it returns false on error. WARNING: always check the return value of send.
-* `address.call(__payload__)`: low-level `CALL` functionācan construct an arbitrary message call with a data payload. Returns false on error. WARNING: unsafe.
-* `address.delegatecall(__payload__)`: low-level `DELEGATECALL` function, like `callcode(...)` but with the full msg context seen by the current contract. Returns false on error. WARNING: advanced use only!
-
-
-
-
-##### built-in functions
-
-* `addmod`, `mulmod`: for modulo addition and multiplication. for example, `addmod(x,y,k)` calculates `(x + y) % k`.
-* `keccak256`, `sha256`, `sha3`, `ripemd160`: calculate hashes with various standard hash algorithms.
-* `ecrecover`: recovers the address used to sign a message from the signature.
-* `selfdestruct(__recipient_address__)`: deletes the current contract, sending any remaining ether in the account to the recipient address.
-* `this`: address of the currently executing contract account.
-* [list of precompiled contracts](https://www.evm.codes/precompiled?fork=arrowGlacier)
-
-
-
-##### what is considered modifying state
-
-- writing to state variables
-- emitting events
-- creating other contracts
-- sending ether via calls
-- using selfdestruct
-- using low-level calls
-- calling any function not marked view or pure
-- using inline assembly that contains certain opcodes
-
-
-
-
-
-
-
----
-
-### solidity vs. python/js/c++
-
-
-
-
-from python, we get:
-- modifiers
-- multiple inheritances
-
-from js we get:
-- function-level scoping
-- the `var` keyword
-
-from c/c++ we get:
-
-- scoping: variables are visible from the point right after their declaration until the end of the smallest {}-block that contains the declaration.
-- the good ol' value types (passed by value, so they are alway copied to the stack) and reference types (references to the same underlying variable).
-- however, look how cool: a variable that is declared will have an initial default value whose byte-representation is all zeros.
-- int and uint integers, with uint8 to uint256 in step of 8.
-
-from being statically-typed:
-- the type of each variable (local and state) needs to be specified at compile-time (as opposed to runtime).
-
-
-
-you start files with the `SPDX License Identifier (`// SPDX-License-Identifier: MIT`)`. SPDX stands for software package data exchange. The compiler will include this in the bytecode metadata and make it machine readable.
-
-
-
-**pragmas:** directives that are used to enable certain compiler features and checks.
-
-version Pragma indicates the specific Solidity compiler version. It does not change the version of the compiler, though, so yeah, you will get an error if it does not match the compiler.
-
-other types are Compiler version, ABI coder version, SMTCheker.
-
-
-
-The best-practices for layout in a contract are:
-1. state variables
-2. events
-3. modifiers
-4. constructors
-5. functions
-
-
-
-
-**natspec comments**: Also known as the "ethereum natural language specification format". Written as triple slashes (`///`) or double asterisk block
-`(/**...*/)`, directly above function declarations or statements to generate documentation in `JSON` format for developers and end-users. These are some tags:
-
-* `@title`: describe the contract/interface
-* `@author`
-* `@notice`: explain to an end user what it does
-* `@dev`: explain to a dev
-* `@param`: document params
-* `@return`: any returned variable
-* `@inheritdoc`: copies missing tags from the base function (must be followed by contract name)
-* `@custom`: anything application-defined
-
-
-
-
-
-**events**: an abstraction on top of EVM's logging: emitting events cause the arguments to be stored in the transaction's log (which are associated with the address of the contract). events are emitted using **emit**.
-
-events are especially useful for light clients and DApp services, which can "watch" for specific events and report them to the user interface, or make a change in the state of the application to reflect an event in an underlying contract.
-
-
-
-
----
-
-### type of variables
-
-
-
-**address types**. the address type comes in two types:
-
-1. holds a 20 byte value (the size of an Ethereum address)
-2. address payable: with additional members transfer and send. address payable is an address you can send Ether to (while plain address not).
-
-explicit conversion from address to address payable can be done with `payable()`.
-explicit conversion from or to address is allowed for `uint160`, integer literals, `byte20`, and contract types
-
-the members of address type are pretty interesting: `.balance`, `.code`, `.codehash`, `.transfer`, `.send`, `.call`, `.delegatecall`, `.staticcall`.
-
-
-
-**fixed-size Byte Arrays**: bytes1, bytes2, bytes3, ā¦, bytes32 hold a sequence of bytes from one to up to 32. The type `byte[]` is an array of bytes, but due to padding rules, it wastes 31 bytes of space for each element, so it's better to use `bytes()`
-
-
-
-
-**state variables**: variables that can be accessed by all functions of the contract and values are permanently stored in the contract storage.
-
-**state visibility specifiers**: these are state variables that define how the methods will be accessed:
-
-- `public`: part of the contract interface and can be accessed internally or via messages.
-- `external`: like public functions, but cannot be called within the contract.
-- `internal`: can only be accessed internally from within the current contracts (or contracts deriving from it).
-- `private`: can only be accessed from the contract they are defined in and not in derived contracts.
-- `pure`: neither reads nor writes any variables in storage. It can only operate on arguments and return data, without reference to any stored data. Pure functions are intended to encourage declarative-style programming without side effects or state.
-- `payable`: can accept incoming payments. Functions not declared as payable will reject incoming payments. There are two exceptions, due to design decisions in the EVM: coinbase payments and `SELFDESTRUCT` inheritance will be paid even if the fallback function is not declared as payable.
-
-
-
-**immutability**: state variables can be declared as constant or immutable, so they cannot be modified after the contract has been constructed. their difference is beautiful:
-
-**for constant variables, the value is fixed at compile-time; for immutable variables, the value can still be assigned at construction time (in the constructor or point of declation)**
-
-there is an entire gas cost thing too. For constant variables, the expression assigned is copied to all the places, and re-evaluated each time (local optimizations are possible). For immutable variables, the expression is evaluated once at constriction time and their value is copied to all the places in the code they are accessed, on a reserved 32 bytes, becoming usually more expensive than constant.
-
-
-
----
-
-### functions
-
-
-
-**functions modifiers**: used to change the behavior of functions in a declarative way, so that the function's control flow continues after the "_" in the preceding modifier. This symbol can appear in the modifier multiple times.
-
-the underscore followed by a semicolon is a placeholder that is replaced by the code of the function that is being modified. Essentially, the modifier is "wrapped around" the modified function, placing its code in the location identified by the underscore character.
-
-to apply a modifier, you add its name to the function declaration. More than one modifier can be applied to a function; they are applied in the sequence they are declared, as a space-separated list.
-
-```
-function destroy() public onlyOwner {
-```
-
-
-
-**function visibility specifiers**: these are how visibility works for functions:
-
-- `public`: part of the contract interface and can be either called internally or via messages.
-- `external`: part of the contract interface, and can be called from other contracts and via transactions. Here is the interesting part: an external function `func` cannot be called internally, so `func()` would not work. But `this.func()` does.
-- `internal`: can only be accessed from within the current contract or contracts deriving from it.
-- `private`: can only be accessed from the contract they are defined in and not even in derived contracts
-
-
-
-**function mutability specifiers**:
-
-- `view` functions can read the contract state but not modify it: enforced at runtime via STATICALL opcode.
-- `pure` functions can neither read a contract nor modify it.
-- only view can be enforced at the EVM level, not pure.
-
-
-
-**overloading**: a contract can have multiple functions of the same name but with different parameter types. they are matched by the arguments supplied in the function call š¬.
-
-
-
-
----
-
-### data structures
-
-
-
-- `structs`: custom-defined types that can group several variables of same/different types together to create a custom data structure.
-- `enums`: used to create custom types with a finite set of constants values. Cannot have more than 256 members.
-
-
-
-**constructors**: when a contract is created, the function with *constructor* is executed once and then the final code of the contract is stored on the blockchain (all public and external functions, but not the constructor code or internal functions called by it).
-
-
-
-**receive function**: a contract can have ONE *receive* function (*receive() external payable {...}*) without the function keyword, and no arguments and no return and... have `external` and `payable`. this is the function on plain ether transfers via `send()` or `transfer()`.
-
-interesting facts:
-
-- receive is executed on a call to the contract with empty calldata.
-- receive might only rely on 2300 gas being available.
-- a contract without Receive can actually receive Ether as a recipient of a coinbase transaction (miner block reward) or as a destination of `selfdestruct`.
-- a contract cannot react to the Ether transfer above.
-
-
-
-**falback function**: kinda in the same idea, a contract can have ONE *fallback* function, which must have external visibility.
-
-- fallback is executed on a call to the contract if none of the other functions match the given function signature or no data was supplied and there is not receive Ether function.
-
-
-
-
-**transfer:** the transfer function fails if the balance of the contract is not enough or if the transfer is rejected by the receiving account, revering on failure.
-
-
-
-**send:** low-level counterpart of transfer, however, if the execution fails then send only returns false (return value must be checked by the caller).
-
-
-
-----
-
-### data management
-
-
-
-* the evm manages different kinds of data depending on their context:
-
-
-
-* **stack**: the evm operates on a virtual stack, which has a maximum size of 1024, stack items have a size of 256 bits (the evm is a 256-bit word machine, which facilitates keccak256 hash scheme and elliptic-curve). the opcodes to modify the stack are: `POP` (remove from stack), `PUSH n` (places the `n` butes item into the stack), `DUP n` (duplicates the `n`th stack item), `SWAP n` (exchanges the first and the `n`th stack item).
-
-* **calldata**: read-only byte-addressable space where the data parameter of a tx or call is held. unlike the stack, to use this data, you have to specify an exact byte offset and number of bytes to read. the opcodes include: `CALLDATASIZE` (get size of tx data), `CALLDATALOAD` (loads 32 byte of tx data onto the stack), `CALLDATACOPY` (copies the number of bytes of the tx data to memory). there are also the inline assembly versions: `calldatasize`, `calldataload`, calldatacopy`. they can be called through:
-
-```
-assembly {
-}
-```
-
-* **memory**: volatile read-write byte-addressable space (store data during execution) initiallized as zero. the evm opcodes are `MLOAD` (loads a word into the stack), `MSTORE` (saves a word to memory), `MSTORE8` (saves a byte to memory). gas costs since memory loads (MLOADs) are significantly cheaper in gas than SLOADs.
-
-* **storage**: persistant read-write word-addressable space for contracts, addressed by words. it's a key-value mapping of 2**256 slots of 32 bytes each. gas to save data into storage is one of the highest operations. the evm opcodes are: `SLOAD` (loads a word from storage to stack), `SSTORE` (saves a word to storage).
- * bitpack loading: storing multiple variables in a single 32-byts slot by ordering the byte size
- * fixed-length arrays: takes a predetermined amount of slots.
- * dynamic-length arrays: new elements assign slots after deployment (handled by the evm with keccak256 hashing)
- * mappings: dynamic type with key hashes
-
-
-
-
-
-----
-
-### calling another contract
-
-
-
-**call/delegatecall/ataticall**: ued to interface with contracts that do not adhere to ABI, or to give more direct control over encoding. they all take a single bytes memory parameter and return the success condition (as a bool) and the return data (byte memory).
-
-with `DELEGATECALL`, only the code of the given address is used but all other aspects are taken from the current contract. The purpose is to use logic code that is stored in the callee contract but operates on the state of the caller contract.
-
-with `STATCALL`, the execution will revert if the called function modifies the state in any way.
-
-
-
-
-**creating a new instance**:
-
-* the safest way to call another contract is if you create that other contract yourself.
-* to do this, you can simply instantiate it, using the keyword `new`, as in other object-oriented languages. This keyword will create the contract on the blockchain and return an object that you can use to reference it.
-
-```
-contract Token is Mortal {
- Faucet _faucet;
-
- constructor() {
- _faucet = new Faucet();
- }
-}
-```
-
-
-
-**addressing an existing instance**:
-
-* another way you can call a contract is by casting the address of an existing instance of the contract.
-* with this method, you apply a known interface to an existing instance.
-* this is much riskier than the previous mechanism, because we donāt know for sure whether that address actually is a faucet object.
-
-```
-import "Faucet.sol";
-
-contract Token is Mortal {
-
- Faucet _faucet;
-
- constructor(address _f) {
- _faucet = Faucet(_f);
- _faucet.withdraw(0.1 ether);
- }
-}
-
-```
-
-
-
-
-
-----
-
-### block and tx properties**
-
-- `blockhash`
-- `block.chainid`
-- `block.coinbase`
-- `block.difficulty`
-- `block.gaslimit`
-- `block.number`
-- `block.timestamp`
-- `msg.data`
-- `msg.sender`
-- `msg.sig`
-- `msg.value`
-- `tx.gasprice`
-- `gasleft`
-- `tx.origin`
-
-
-
-**randomness**. Not cute shit: you cannot rely on block.timestamp or blockhash as a source of randomness, as they can be influenced by miners to some degree.
-
-
-
----
-
-### ABI encoding and decoding functions
-
-
-
-- `abi.decode`
-- `abi.encode`
-- `abi.encodePacked`
-- `abi.encodeWithSelector`
-- `abi.encodeWithSignature`
-
-
-
-----
-
-### error handling
-
-
-
-- `assert()`: causes a panic error and reverts if the condition is not met
-- `require()`: reverts if the condition is not met
-- `revert()`: abort execution and revert state changes
-
diff --git a/token_standards/README.md b/token_standards/README.md
deleted file mode 100644
index c79680b..0000000
--- a/token_standards/README.md
+++ /dev/null
@@ -1,41 +0,0 @@
-## ethereum token standards
-
-### tl; dr
-
-* EIP stands for Ethereum Improvement Proposals.
-* ERC stands for Ethereum request for comments (technical documents written by Ethereum developers for Ethereum community).
-* Each such document contains a set of rules required to implement tokens for the Ethereum ecosystem.
-
-
-
-
-
----
-
-### erc-20
-
-
-* In the case of ERC20, a transaction sending ether to an address changes the state of an address.
- - a transaction transferring a token to an address only changes the state of the token contract, not the state of the recipient address.
-* one of the main reasons for the success of EIP-20 tokens is in the interplay between `approve` and `transferFrom`, which allows for tokens to not
-only be transferred between externally owned accounts (EOA).
- - but to be used in other contracts under application specific conditions by abstracting away `msg.sender` as the mechanism for token access control.
-* a limiting factor lies from the fact that the EIP-20 `approve` function is defined in terms of `msg.sender`.
- - this means that userās initial action involving EIP-20 tokens must be performed by an EOA.
- - if the user needs to interact with a smart contract, then they need to make 2 transactions (`approve` and the smart contract internal call `transferFrom`), with gas costs.
-
-
-
----
-
-### in this dir
-
-* [ERC20](erc20.md)
-* [ERC777](erc777.md)
-* [ERC721](erc721.md)
-
-
-
----
-
-### resources
diff --git a/token_standards/erc20.md b/token_standards/erc20.md
deleted file mode 100644
index 45bcff2..0000000
--- a/token_standards/erc20.md
+++ /dev/null
@@ -1,73 +0,0 @@
-## ERC20
-
-
-
-* The ERC20 standard defines a common interface for contracts implementing this token, such that any compatible token can be accessed and used in the same way.
-
-
-
-### ERC20-compliant token contract
-
-* totalSupply
-Returns the total units of this token that currently exist. ERC20 tokens can have a fixed or a variable supply.
-
-* balanceOf
-Given an address, returns the token balance of that address.
-
-* transfer
-Given an address and amount, transfers that amount of tokens to that address, from the balance of the address that executed the transfer.
-
-* transferFrom
-Given a sender, recipient, and amount, transfers tokens from one account to another. Used in combination with approve.
-
-* approve
-Given a recipient address and amount, authorizes that address to execute several transfers up to that amount, from the account that issued the approval.
-
-* allowance
-Given an owner address and a spender address, returns the remaining amount that the spender is approved to withdraw from the owner.
-
-* Transfer
-Event triggered upon a successful transfer (call to transfer or transferFrom) (even for zero-value transfers).
-
-* Approval
-Event logged upon a successful call to approve.
-
-
-
----
-
-### ERC20 optional functions
-
-In addition to the required functions listed in the previous section, the following optional functions are also defined by the standard:
-
-* name
-Returns the human-readable name (e.g., "US Dollars") of the token.
-
-* symbol
-Returns a human-readable symbol (e.g., "USD") for the token.
-
-* decimals
-Returns the number of decimals used to divide token amounts. For example, if decimals is 2, then the token amount is divided by 100 to get its user representation.
-
-
-
----
-
-### The ERC20 interface defined in Solidity
-
-
-```
-contract ERC20 {
- function totalSupply() constant returns (uint theTotalSupply);
- function balanceOf(address _owner) constant returns (uint balance);
- function transfer(address _to, uint _value) returns (bool success);
- function transferFrom(address _from, address _to, uint _value) returns
- (bool success);
- function approve(address _spender, uint _value) returns (bool success);
- function allowance(address _owner, address _spender) constant returns
- (uint remaining);
- event Transfer(address indexed _from, address indexed _to, uint _value);
- event Approval(address indexed _owner, address indexed _spender, uint _value);
-}
-```
-
diff --git a/workspace/remix-IDE.md b/workspace/remix-IDE.md
deleted file mode 100644
index 58ea070..0000000
--- a/workspace/remix-IDE.md
+++ /dev/null
@@ -1,68 +0,0 @@
-## Remix IDE
-
-
-
-Remix IDE is an open source web3 application and it's used for the entire journey of smart contract development.
-
-
-
-
-
-
-
-
-* Everything in Remix is a plugin. The plugin mamanger is the place to load functionalities and create your own plugins.
-* By default, Remix stores files in Workspaces, which are folders in the browser's local storage.
-* You can publish all files from current workspace to a gist, using the Gist API.
-
-
-
-
-#### Compiler (Solidity)
-
-* You can compile (and deploy) contracts with versions of Solidity older than 0.4.12. However, the older compilers used a legacy AST.
-* The "fork selection" dropdown list allows to compile code against a specific ehtereum hard fork.
-
-
-
-
-#### Optimization
-
-* The optimizer tries to simplify complicated expressions, which reduces both code size and execution cost. It can reduce gas needed for contract deployment as well as for external calls made to the contract.
-
-
-
-
-#### Environment
-
-* `JavaScript VM`: All transactions will be executed in a sandbox blockchain in the browser.
-* `Injected Provider`: Metamaask is an example of a profiver that inject web3.
-* `Web3 Provider`: Remix will connect to a remote node (you need to provide the URL to the selected provider: geth, parity or any ethereum client)
-
-
-
-
-#### Setup
-
-* Gas Limit: sets the amount of ETH, WEI, GWEI that is sent to ta contract or a payable function.
-* Deploy: sends a transaction that deplpys the selected contract.
-* atAdress: used to access a contract whtat has already been deployed (does not cost gas).
-* To interact with a contract using the ABI, create a new file in Remix, with extension `.abi`.
-* The Recorder is a tool used to save a bunch of transactions in a JSON file and rerun them later either in the same environment or in another.
-* The Debugger shows the contract's state while stepping through a transaction.
-* Using generated sources will make it easier to audit your contracts.
-* Static code analysis can be done by a plugin, so that you can examine the code for security vulnerabilities, bad development practices, etc.
-* Hardhat integration can be done with `hardhat.config.js` (Hardhat websocket listener should run at `65522`). Hardhat provider is a plugin for Remix IDE.
-
-
-
-
-#### Generate artifacts
-
-When a compilation for a Solidity file succeeds, Remix creates three Json files for each compiled contract, that can be seen in the `File Explorers plugin`:
-
-1. `artifacts/.json`: contains links to libraries, the bytecode, gas estimation, the ABI.
-2. `articfacts/.json`: contains the metadata from the output of Solidity compilation.
-3. `artifcats/build-info/.json`: contains info about `solc` compiler version, compiler input and output.
-
-