mirror of
https://github.com/autistic-symposium/web3-starter-sol.git
synced 2025-04-22 16:59:08 -04:00
add_files
This commit is contained in:
parent
6a1272df4c
commit
fb77004daf
28
README.md
28
README.md
@ -2,13 +2,37 @@
|
||||
|
||||
<br>
|
||||
|
||||
### in this repo
|
||||
#### start with [solidity tl; dr](solidity_tldr.md)
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
### solidity resources
|
||||
### in this repo
|
||||
|
||||
|
||||
#### learning
|
||||
|
||||
* [set your workspace](workspace)
|
||||
* [tokens standard](token_standards)
|
||||
* [boilerplates](boilerplates)
|
||||
* [saving gas](saving_gas)
|
||||
* [abi enconding](abi_enconding)
|
||||
* [topics]()
|
||||
* [tests](tests)
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
#### boilerplates and code
|
||||
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
### resources
|
||||
|
||||
* [solidity docs](https://docs.soliditylang.org/en/v0.8.12/)
|
||||
* [openzeppelin docs](https://docs.openzeppelin.com/)
|
||||
|
30
abi_enconding/README.md
Normal file
30
abi_enconding/README.md
Normal file
@ -0,0 +1,30 @@
|
||||
## 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.
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
* *other ABI Encodings
|
||||
* address payable -> address
|
||||
* contract -> address
|
||||
* enum -> uint8
|
||||
* struct -> tuple of elementry types
|
||||
|
||||
---
|
||||
|
||||
### resources
|
12
boilerplates/README.md
Normal file
12
boilerplates/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
## boilerplates
|
||||
|
||||
### in this dir
|
||||
|
||||
* [learning](learning)
|
||||
* [solidity 101](solidity_101)
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
### resources
|
32
boilerplates/learning/hello-world.sol
Normal file
32
boilerplates/learning/hello-world.sol
Normal file
@ -0,0 +1,32 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
58
boilerplates/learning/token.sol
Normal file
58
boilerplates/learning/token.sol
Normal file
@ -0,0 +1,58 @@
|
||||
pragma solidity ^0.5.10;
|
||||
|
||||
contract Token {
|
||||
// An `address` is comparable to an email address - it's used to identify an account on Ethereum.
|
||||
// Addresses can represent a smart contract or an external (user) accounts.
|
||||
// Learn more: https://solidity.readthedocs.io/en/v0.5.10/types.html#address
|
||||
address public owner;
|
||||
|
||||
// A `mapping` is essentially a hash table data structure.
|
||||
// This `mapping` assigns an unsigned integer (the token balance) to an address (the token holder).
|
||||
// Learn more: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types
|
||||
mapping (address => uint) public balances;
|
||||
|
||||
// Events allow for logging of activity on the blockchain.
|
||||
// Ethereum clients can listen for events in order to react to contract state changes.
|
||||
// Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events
|
||||
event Transfer(address from, address to, uint amount);
|
||||
|
||||
// Initializes the contract's data, setting the `owner`
|
||||
// to the address of the contract creator.
|
||||
constructor() public {
|
||||
// All smart contracts rely on external transactions to trigger its functions.
|
||||
// `msg` is a global variable that includes relevant data on the given transaction,
|
||||
// such as the address of the sender and the ETH value included in the transaction.
|
||||
// Learn more: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
// Creates an amount of new tokens and sends them to an address.
|
||||
function mint(address receiver, uint amount) public {
|
||||
// `require` is a control structure used to enforce certain conditions.
|
||||
// If a `require` statement evaluates to `false`, an exception is triggered,
|
||||
// which reverts all changes made to the state during the current call.
|
||||
// Learn more: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
|
||||
|
||||
// Only the contract owner can call this function
|
||||
require(msg.sender == owner, "You are not the owner.");
|
||||
|
||||
// Enforces a maximum amount of tokens
|
||||
require(amount < 1e60, "Maximum issuance exceeded");
|
||||
|
||||
// Increases the balance of `receiver` by `amount`
|
||||
balances[receiver] += amount;
|
||||
}
|
||||
|
||||
// Sends an amount of existing tokens from any caller to an address.
|
||||
function transfer(address receiver, uint amount) public {
|
||||
// The sender must have enough tokens to send
|
||||
require(amount <= balances[msg.sender], "Insufficient balance.");
|
||||
|
||||
// Adjusts token balances of the two addresses
|
||||
balances[msg.sender] -= amount;
|
||||
balances[receiver] += amount;
|
||||
|
||||
// Emits the event defined earlier
|
||||
emit Transfer(msg.sender, receiver, amount);
|
||||
}
|
||||
}
|
5
boilerplates/solidity_101/.env_sample
Normal file
5
boilerplates/solidity_101/.env_sample
Normal file
@ -0,0 +1,5 @@
|
||||
API_URL = "https://eth-rinkeby.alchemyapi.io/v2/<project>"
|
||||
PUBLIC_KEY =
|
||||
PRIVATE_KEY =
|
||||
METADATA_URL = <pinata IPFS cid dor metadata>"
|
||||
CONTRACT_ADDRESS =
|
20
boilerplates/solidity_101/README.md
Normal file
20
boilerplates/solidity_101/README.md
Normal file
@ -0,0 +1,20 @@
|
||||
## get started with hardhat + erc721
|
||||
|
||||
|
||||
1. Compile contract:
|
||||
|
||||
```
|
||||
npx hardhat compile
|
||||
```
|
||||
|
||||
2. Deploy contract:
|
||||
|
||||
```
|
||||
npx hardhat run scripts/deploy-contract.js --network rinkeby
|
||||
```
|
||||
|
||||
3. Mint NFT:
|
||||
|
||||
```
|
||||
node scripts/mint-nft.js
|
||||
```
|
28
boilerplates/solidity_101/contracts/MiaNFT.sol
Normal file
28
boilerplates/solidity_101/contracts/MiaNFT.sol
Normal file
@ -0,0 +1,28 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity >=0.7.3 <0.9.0;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
|
||||
import "@openzeppelin/contracts/utils/Counters.sol";
|
||||
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||
|
||||
|
||||
contract MiaNFT is ERC721, Ownable {
|
||||
|
||||
using Counters for Counters.Counter;
|
||||
Counters.Counter private _tokenIds;
|
||||
|
||||
constructor() public ERC721("Mia's NFT, "NFT") {}
|
||||
|
||||
function mintNFT(address recipient, string memory tokenURI)
|
||||
public onlyOwner
|
||||
returns (uint256)
|
||||
{
|
||||
_tokenIds.increment();
|
||||
|
||||
uint256 newItemId = _tokenIds.current();
|
||||
_mint(recipient, newItemId);
|
||||
_setTokenURI(newItemId, tokenURI);
|
||||
|
||||
return newItemId;
|
||||
}
|
||||
}
|
19
boilerplates/solidity_101/hardhat.config.js
Normal file
19
boilerplates/solidity_101/hardhat.config.js
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @type import('hardhat/config').HardhatUserConfig
|
||||
*/
|
||||
require('dotenv').config();
|
||||
require("@nomiclabs/hardhat-ethers");
|
||||
|
||||
const { API_URL, PRIVATE_KEY } = process.env;
|
||||
|
||||
module.exports = {
|
||||
solidity: "0.7.3",
|
||||
defaultNetwork: "rinkeby",
|
||||
networks: {
|
||||
hardhat: {},
|
||||
rinkeby: {
|
||||
url: API_URL,
|
||||
accounts: [`0x${PRIVATE_KEY}`]
|
||||
}
|
||||
},
|
||||
}
|
23
boilerplates/solidity_101/package.json
Normal file
23
boilerplates/solidity_101/package.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "MiaNFT",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Mia von Steinkirch",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@nomiclabs/hardhat-ethers": "^2.0.2",
|
||||
"@nomiclabs/hardhat-waffle": "^2.0.1",
|
||||
"@openzeppelin/contracts": "^3.1.0-solc-0.7",
|
||||
"chai": "^4.3.4",
|
||||
"ethereum-waffle": "^3.4.0",
|
||||
"ethers": "^5.4.6",
|
||||
"hardhat": "^2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@alch/alchemy-web3": "^1.1.4",
|
||||
"dotenv": "^10.0.0"
|
||||
}
|
||||
}
|
14
boilerplates/solidity_101/scripts/deploy-contract.js
Normal file
14
boilerplates/solidity_101/scripts/deploy-contract.js
Normal file
@ -0,0 +1,14 @@
|
||||
async function main() {
|
||||
const nft = await ethers.getContractFactory("MiaNFT");
|
||||
|
||||
const nft_deploy = await nft.deploy();
|
||||
console.log(" ⛓🧱✨ Contract address:", nft_deploy.address);
|
||||
console.log(" ➡️ (Please add this string to .env)");
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
41
boilerplates/solidity_101/scripts/mint-nft.js
Normal file
41
boilerplates/solidity_101/scripts/mint-nft.js
Normal file
@ -0,0 +1,41 @@
|
||||
require('dotenv').config();
|
||||
|
||||
const PUBLIC_KEY = process.env.PUBLIC_KEY;
|
||||
const PRIVATE_KEY = process.env.PRIVATE_KEY;
|
||||
const API_URL = process.env.API_URL;
|
||||
const METADATA_URL = process.env.METADATA_URL;
|
||||
const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESS;
|
||||
const { createAlchemyWeb3 } = require("@alch/alchemy-web3");
|
||||
const web3 = createAlchemyWeb3(API_URL);
|
||||
const contract = require("../artifacts/contracts/MiaNFT.sol/MiaNFT.json");
|
||||
const nftContract = new web3.eth.Contract(contract.abi, CONTRACT_ADDRESS);
|
||||
|
||||
async function mintNFT(tokenURI) {
|
||||
|
||||
const nonce = await web3.eth.getTransactionCount(PUBLIC_KEY, 'latest');
|
||||
|
||||
const transaction = {
|
||||
'from': PUBLIC_KEY,
|
||||
'to': CONTRACT_ADDRESS,
|
||||
'nonce': nonce,
|
||||
'gas': 500000,
|
||||
'maxPriorityFeePerGas': 1999999987,
|
||||
'data': nftContract.methods.mintNFT(PUBLIC_KEY, tokenURI).encodeABI()
|
||||
};
|
||||
|
||||
const sign = web3.eth.accounts.signTransaction(transaction, PRIVATE_KEY);
|
||||
sign.then((signedTransaction) => {
|
||||
|
||||
web3.eth.sendSignedTransaction(signedTransaction.rawTransaction, function(e, hash) {
|
||||
if (!e) {
|
||||
console.log("💾 Transaction hash: ", hash);
|
||||
} else {
|
||||
console.log("ERROR:", e)
|
||||
}
|
||||
});
|
||||
}).catch((e) => {
|
||||
console.log("ERROR:", e);
|
||||
});
|
||||
}
|
||||
|
||||
mintNFT(METADATA_URL);
|
13
events/README.md
Normal file
13
events/README.md
Normal file
@ -0,0 +1,13 @@
|
||||
## solidity topics
|
||||
|
||||
### tl; dr
|
||||
|
||||
* solidity provides two types of events:
|
||||
- anonymous: 4 topics may be indexed, and there is not signature hash (no filter)
|
||||
- non-anonymous (default): up to 3 topics may be indexed, since the first topic is reserved to the event signature (filter)
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
### resources
|
102
saving_gas/README.md
Normal file
102
saving_gas/README.md
Normal file
@ -0,0 +1,102 @@
|
||||
## tricks to save gas
|
||||
|
||||
|
||||
### tl; dr
|
||||
|
||||
- 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, and sending a transaction costs 21,000 gas.
|
||||
- brute force hashes of function names to find those that start 0000, so this can save around 50 gas.
|
||||
- avoid calls to other contracts.
|
||||
- ++i uses 5 gas less than i++.
|
||||
- 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.
|
||||
<br>
|
||||
|
||||
#### 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.
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
---
|
||||
|
||||
### resources
|
||||
|
||||
|
||||
|
||||
* [truffle contract size](https://github.com/IoBuilders/truffle-contract-size)
|
||||
* [solidity gas optimizations](https://mirror.xyz/haruxe.eth/DW5verFv8KsYOBC0SxqWORYry17kPdeS94JqOVkgxAA)
|
||||
* [hardhat](https://medium.com/@thelasthash/%EF%B8%8F-gas-optimization-with-hardhat-1e553eaea311)
|
||||
* [foundry](https://book.getfoundry.sh/forge/gas-reports)
|
||||
|
||||
|
416
solidity_tldr.md
Normal file
416
solidity_tldr.md
Normal file
@ -0,0 +1,416 @@
|
||||
|
||||
## solidity tl;dr
|
||||
|
||||
<br>
|
||||
|
||||
### predefined global variables and functions
|
||||
|
||||
<br>
|
||||
|
||||
* 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.
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
#### 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.
|
||||
|
||||
<br>
|
||||
|
||||
#### tx
|
||||
|
||||
* tx.gasprice: gas price in the calling transaction.
|
||||
* tx.origin: address of the originating EOA for this transaction. WARNING: unsafe!
|
||||
|
||||
<br>
|
||||
|
||||
#### 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).
|
||||
|
||||
<br>
|
||||
|
||||
#### 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!
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
#### 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.
|
||||
|
||||
<br>
|
||||
|
||||
#### 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
### solidity vs. python/C++
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
From Python, we get:
|
||||
- modifiers
|
||||
- multiple inheritances
|
||||
|
||||
From JavaScript 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).
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
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.
|
||||
|
||||
<br>
|
||||
|
||||
**Pragmas.** Big thing. 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.
|
||||
|
||||
<br>
|
||||
|
||||
The best-practices for layout in a contract are:
|
||||
1. state variables
|
||||
2. events
|
||||
3. modifiers
|
||||
4. constructors
|
||||
5. functions
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
**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)
|
||||
* @custon: anything application-defined
|
||||
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
**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.
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
---
|
||||
|
||||
### variables
|
||||
|
||||
<br>
|
||||
|
||||
**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.
|
||||
|
||||
<br>
|
||||
|
||||
**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()
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
**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.** This is important. 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.
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
### functions
|
||||
|
||||
<br>
|
||||
|
||||
**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 {
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
**Function Visibility Specifiers**. Super uber important. 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
|
||||
|
||||
<br>
|
||||
|
||||
**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.
|
||||
|
||||
<br>
|
||||
|
||||
**Overloading**. Okay, this one is hardcore: 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 😬.
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
### data structures
|
||||
|
||||
<br>
|
||||
|
||||
- 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.
|
||||
|
||||
<br>
|
||||
|
||||
**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).
|
||||
|
||||
<br>
|
||||
|
||||
**Receive function**. So this is interesting. 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.
|
||||
|
||||
<br>
|
||||
|
||||
**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.
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
**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.
|
||||
|
||||
<br>
|
||||
|
||||
**Send.** Low-level counterpart of transfer, however, if the execution fails then send only returns false (return value must be checked by the caller).
|
||||
|
||||
<br>
|
||||
|
||||
----
|
||||
|
||||
## calling another contract
|
||||
|
||||
<br>
|
||||
|
||||
**Call/Delegatecall/Staticall**. 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 staticall, the execution will revert if the called function modifies the state in any way.
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
### 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();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
### 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);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
### raw call, delegatecall
|
||||
|
||||
* Solidity offers some even more "low-level" functions for calling other contracts.
|
||||
* These correspond directly to EVM opcodes of the same name and allow us to construct a contract-to-contract call manually.
|
||||
* As such, they represent the most flexible and the most dangerous mechanisms for calling other contracts.
|
||||
* It can expose your contract to a number of security risks, most importantly reentrancy.
|
||||
|
||||
```
|
||||
contract Token is Mortal {
|
||||
constructor(address _faucet) {
|
||||
_faucet.call("withdraw", 0.1 ether);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
* Another variant of call is delegatecall, which replaced the more dangerous callcode. A delegatecall is different from a call in that the msg context does not change.
|
||||
* Essentially, delegatecall runs the code of another contract inside the context of the execution of the current contract.
|
||||
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
----
|
||||
|
||||
### data
|
||||
|
||||
<br>
|
||||
|
||||
**Data Location.** Every reference type has an additional annotation with the data location where it is stored:
|
||||
|
||||
* memory: lifetime is limited to an external function call
|
||||
* storage: limited to the lifetime of a contract and the location where the state variables are stored
|
||||
* calldata: non-modifiable, non-persistent area where function arguments are stored and behaves mostly like memory
|
||||
|
||||
<br>
|
||||
|
||||
**Block and Transaction Properties.** Cute shit.
|
||||
|
||||
- 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
|
||||
|
||||
<br>
|
||||
|
||||
**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.
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
### ABI encoding and decoding functions
|
||||
|
||||
<br>
|
||||
|
||||
- abi.decode
|
||||
- abi.encode
|
||||
- abi.encodePacked
|
||||
- abi.encodeWithSelector
|
||||
- abi.encodeWithSignature
|
||||
|
||||
<br>
|
||||
|
||||
----
|
||||
|
||||
### error handling
|
||||
|
||||
<br>
|
||||
|
||||
- assert(): causes a panic error and revert if the condition is not met
|
||||
- require(): reverts if the condition is not met
|
||||
- revert(): abort execution and revert state changes
|
||||
|
34
tests/README.md
Normal file
34
tests/README.md
Normal file
@ -0,0 +1,34 @@
|
||||
## tests in solidity
|
||||
|
||||
### tl; dr
|
||||
|
||||
#### 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.
|
||||
|
||||
|
||||
|
||||
#### unit testing
|
||||
|
||||
|
||||
* [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)
|
||||
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
### 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)
|
63
tests/unit-testing.md
Normal file
63
tests/unit-testing.md
Normal file
@ -0,0 +1,63 @@
|
||||
## basic Unit testing
|
||||
|
||||
<br>
|
||||
|
||||
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
|
||||
|
||||
<br>
|
||||
|
||||
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.
|
||||
|
||||
|
41
token_standards/README.md
Normal file
41
token_standards/README.md
Normal file
@ -0,0 +1,41 @@
|
||||
## 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.
|
||||
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
### 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.
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
### in this dir
|
||||
|
||||
* [ERC20](erc20.md)
|
||||
* [ERC777](erc777.md)
|
||||
* [ERC721](erc721.md)
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
### resources
|
73
token_standards/erc20.md
Normal file
73
token_standards/erc20.md
Normal file
@ -0,0 +1,73 @@
|
||||
## ERC20
|
||||
|
||||
<br>
|
||||
|
||||
* 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.
|
||||
|
||||
<br>
|
||||
|
||||
### 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.
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
### 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.
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
### 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);
|
||||
}
|
||||
```
|
||||
|
41
token_standards/erc721.md
Normal file
41
token_standards/erc721.md
Normal file
@ -0,0 +1,41 @@
|
||||
## ERC721
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
To see the difference between ERC20 and ERC721, look at the internal data structure used in ERC721:
|
||||
|
||||
|
||||
```
|
||||
mapping (uint256 => address) private deedOwner;
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
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.
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
### The ERC721 contract interface specification
|
||||
|
||||
|
||||
```
|
||||
interface ERC721 /* is ERC165 */ {
|
||||
event Transfer(address indexed _from, address indexed _to, uint256 _deedId);
|
||||
event Approval(address indexed _owner, address indexed _approved,
|
||||
uint256 _deedId);
|
||||
event ApprovalForAll(address indexed _owner, address indexed _operator,
|
||||
bool _approved);
|
||||
|
||||
function balanceOf(address _owner) external view returns (uint256 _balance);
|
||||
function ownerOf(uint256 _deedId) external view returns (address _owner);
|
||||
function transfer(address _to, uint256 _deedId) external payable;
|
||||
function transferFrom(address _from, address _to, uint256 _deedId)
|
||||
external payable;
|
||||
function approve(address _approved, uint256 _deedId) external payable;
|
||||
function setApprovalForAll(address _operator, boolean _approved) payable;
|
||||
function supportsInterface(bytes4 interfaceID) external view returns (bool);
|
||||
}
|
||||
```
|
67
token_standards/erc777.md
Normal file
67
token_standards/erc777.md
Normal file
@ -0,0 +1,67 @@
|
||||
## ERC777
|
||||
|
||||
<br>
|
||||
|
||||
* 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
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
<br>
|
||||
|
||||
### ERC777 contract interface specification
|
||||
|
||||
|
||||
```
|
||||
interface ERC777Token {
|
||||
function name() public constant returns (string);
|
||||
function symbol() public constant returns (string);
|
||||
function totalSupply() public constant returns (uint256);
|
||||
function granularity() public constant returns (uint256);
|
||||
function balanceOf(address owner) public constant returns (uint256);
|
||||
|
||||
function send(address to, uint256 amount, bytes userData) public;
|
||||
|
||||
function authorizeOperator(address operator) public;
|
||||
function revokeOperator(address operator) public;
|
||||
function isOperatorFor(address operator, address tokenHolder)
|
||||
public constant returns (bool);
|
||||
function operatorSend(address from, address to, uint256 amount,
|
||||
bytes userData,bytes operatorData) public;
|
||||
|
||||
event Sent(address indexed operator, address indexed from,
|
||||
address indexed to, uint256 amount, bytes userData,
|
||||
bytes operatorData);
|
||||
event Minted(address indexed operator, address indexed to,
|
||||
uint256 amount, bytes operatorData);
|
||||
event Burned(address indexed operator, address indexed from,
|
||||
uint256 amount, bytes userData, bytes operatorData);
|
||||
event AuthorizedOperator(address indexed operator,
|
||||
address indexed tokenHolder);
|
||||
event RevokedOperator(address indexed operator, address indexed tokenHolder);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
68
workspace/remix-IDE.md
Normal file
68
workspace/remix-IDE.md
Normal file
@ -0,0 +1,68 @@
|
||||
## Remix IDE
|
||||
|
||||
<br>
|
||||
|
||||
Remix IDE is an open source web3 application and it's used for the entire journey of smart contract development.
|
||||
|
||||
<br>
|
||||
|
||||
<img width="414" alt="Screen Shot 2022-03-10 at 5 57 22 PM" src="https://user-images.githubusercontent.com/1130416/157715032-63dfbe5d-292d-48e3-8594-04902fb008f6.png">
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
* 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.
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
#### 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.
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
#### 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.
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
#### 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)
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
#### 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.
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
#### 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/<contractName>.json`: contains links to libraries, the bytecode, gas estimation, the ABI.
|
||||
2. `articfacts/<contractName_metadata>.json`: contains the metadata from the output of Solidity compilation.
|
||||
3. `artifcats/build-info/<dynamic_hash>.json`: contains info about `solc` compiler version, compiler input and output.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user