Skip to content

Instantly share code, notes, and snippets.

@JayGwod
Last active November 21, 2021 17:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JayGwod/decf54b91f2a9d4b65f50d238880a71d to your computer and use it in GitHub Desktop.
Save JayGwod/decf54b91f2a9d4b65f50d238880a71d to your computer and use it in GitHub Desktop.
[Solidity, Blockchain, and Smart Contract Course – Beginner to Expert Python Tutorial]Source: https://www.youtube.com/watch?v=M576WGiDBdQ&t=2646s #ETH
from types import SimpleNamespace
from solcx import compile_standard, install_solc
import json
from web3 import Web3
import os
from dotenv import load_dotenv
load_dotenv()
with open("./SimpleStorage.sol", "r") as file:
simple_storage_file = file.read()
# Compile Our Solidity
install_solc("0.6.0")
compile_sol = compile_standard(
{
"language": "Solidity",
"sources": {"SimpleStorage.sol": {"content": simple_storage_file}},
"settings": {
"outputSelection": {
"*": {"*": ["abi", "metadata", "evm.bytecode", "evm.sourceMap"]}
}
},
},
solc_version="0.6.0",
)
with open("compiled_code.json", "w") as file:
json.dump(compile_sol, file)
# get bytecode
bytecode = compile_sol["contracts"]["SimpleStorage.sol"]["SimpleStorage"]["evm"][
"bytecode"
]["object"]
# get abi
abi = compile_sol["contracts"]["SimpleStorage.sol"]["SimpleStorage"]["abi"]
# for connecting to ganache
w3 = Web3(Web3.HTTPProvider("HTTP://127.0.0.1:8545"))
chain_id = 1337
my_address = "0xeB220f017c0D0e0903aA3C0f2e821E20deC2ef9e"
private_key = os.getenv("PRIVATE_KEY")
# Create the contract in python
SimpleStorage = w3.eth.contract(abi=abi, bytecode=bytecode)
# Get the latest transaction
nonce = w3.eth.getTransactionCount(my_address)
# 1. Build a transaction
# 2. Sign a transaction
# 3. Send a transaction
transaction = SimpleStorage.constructor().buildTransaction(
{"chainId": chain_id, "from": my_address, "nonce": nonce}
)
signed_txn = w3.eth.account.sign_transaction(transaction, private_key=private_key)
# Send this signed transaction
print("Deploying contract...")
tx_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction)
tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
print("Deployed!")
# Working with the contract
# Contract Address
# Contract ABI
simple_storage = w3.eth.contract(address=tx_receipt.contractAddress, abi=abi)
# Call -> Simulate making the call and getting a return value
# Transact -> Actually make a state change
# Initial value of favorite number
print(simple_storage.functions.retrieve().call())
print("Updating Contract...")
store_transaction = simple_storage.functions.store(15).buildTransaction(
{"chainId": chain_id, "from": my_address, "nonce": nonce + 1}
)
signed_store_txn = w3.eth.account.sign_transaction(
store_transaction, private_key=private_key
)
send_store_tx = w3.eth.send_raw_transaction(signed_store_txn.rawTransaction)
tx_receipt = w3.eth.wait_for_transaction_receipt(send_store_tx)
print("Updated!")
print(simple_storage.functions.retrieve().call())
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.9.0;
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
// getRoundData and latestRoundData should both raise "No data present"
// if they do not have data to report, instead of returning unset values
// which could be misinterpreted as actual reported values.
function getRoundData(uint80 _roundId)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}
contract FundMe {
mapping(address => uint256) public addressToAmountFunded;
address[] public funders;
address public owner;
constructor() public {
owner = msg.sender;
}
// Payable: be able to accept some type of payment
function fund() public payable {
// $50
uint256 minimumUSD = 50 * 10 ** 18;
require(getConversionRate(msg.value) >= minimumUSD, "You nedd to spend more ETH");
addressToAmountFunded[msg.sender] += msg.value;
funders.push(msg.sender);
}
function getVersion() public view returns (uint256) {
AggregatorV3Interface priceFeed = AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331);
return priceFeed.version();
}
function getPrice() public view returns (uint256) {
AggregatorV3Interface priceFeed = AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331);
(,int256 answer,,,) = priceFeed.latestRoundData();
return uint(answer * 10000000000);
}
function getConversionRate(uint256 ethAmount) public view returns (uint256) {
uint256 ethPrice = getPrice();
uint256 ethAmountInUsed = (ethPrice * ethAmount) / 1000000000000000000;
return ethAmountInUsed;
}
modifier onlyOwner {
require(msg.sender == owner);
_;
}
function withdraw() payable onlyOwner public {
// only want the contract admin/owner
msg.sender.transfer(address(this).balance);
for (uint256 funderIndex=0; funderIndex < funders.length; funderIndex++) {
address funder = funders[funderIndex];
addressToAmountFunded[funder] = 0;
}
funders = new address[](0);
}
}

Lesson 0: Welcome to Blockchain

  1. Bitcoin was the first one to take blockchain mainstream
  2. Bitcoin is like a digital gold
  3. Ethereum allows for smart contracts
  4. Chainlink provides data and external computation to smart contracts
  5. Hybrid Smart Contracts combine on-chain and off-chain componets

Features and advantasges of blockchains and smart contracts

  1. Decentralized
  2. Transparency & Flexibility
  3. Speed and Efficiency
  4. Security & Immutability
  5. Removal of counterparty risk
  6. Trust Minimized Agreements

MetaMask

Concept Can Access Private or Public
Mnemonic All of yout accounts Keep Private!
Private Key 1 of your accounts Keep Private!
Public Address Nothing It's public

Gas term

  • Gas: Measure of computation use
  • Gas Price: How much it costs per unit of gas
  • Gas Limit: Max amount of gas in a transaction

Transaction Fee: Gas Used x Gas Price

  • ie: 21,000 gas @ 1 GWEI per gas = 21,000 GWEI

Gas Price is based off the "demand" of the blockchain.

The more people want to make transactions, the higher the gas price, and therefore the higher the gransaction fees.

Fundamentals of a blockchain

Hash:

  • A unique fixed length string, meant to identify a piece of data. They are created by placing said data into a "hash function"

Genesis Block:

  • The first block in a blockchain

Hash Algorithm:

  • A function that computes data into a unique hash

Mining:

  • The process of finding the "solution" to the blockchain "problem".
  • In out example, the "problem" was to find a hash that starts with four zeros.
  • Nodes get paid for mining blocks.

Block:

  • A list of transactions mined together

Decentralized:

  • Having no single point of authority

Nonce:

  • A "number used once" to find the "solution" to the blockchain problem.
  • It's also used to define the transaction number for an account/address.

Private Key:

  • Only known to the key holder, it's used to "sign" transactions

Public Key:

  • Is derived from your private key. Anyone can "see" it, and use it to verify that a transaction came from you.

Private key ||| > Public Key > Address

  • Private key creates your public key which then can create your address
  • A big barrier here because your private key you want to keep private and your public key and your address can all be public information

Node:

  • A single instance in a decentralized network
  • Anyone can join the network
  • Blockchains are resilient, the most popular chains, like bitcoin and ethereum, have thousands of nodes.
  • Blockchain nodes keep lists of the transactions that occur

Consensus:

  • Consensus is the mechanism used to agree on the state of a blockchain

Consensus protocol:

  1. Chain Selection
  2. Sybil Resistance:
    • A blockchain's ability to defend against users creating a large number of pseudo-anonymous identities to gain a disproportionately advantageous influence over said system.
    • It's basically a way for a blockchain to defend against somebody making a bunch of fake blockchains so that they can get more and more rewards.

PoW and PoS:

  • Proof Of Work (PoW)
  • Proof of Stake (PoS)
    • Proof of stake nodes put up collateral as a sybil resistance mechanism
    • Validators:
      • Nodes are actually randomly chosen to propose the new block and then the rest of the validators will validate if that node has proposed the block honestly

Nakamoto Consensus:

  • A combination of proof of work and longest chain rule

Block Confirmations

  • The number of confirmations is the nmber of additional blocks added on after our transaction went through in a block

Sybil Attack

  • A user creates a whole bunch of pseudo-anonymous accounts to try to influence a network

51% Attack

  • Blockchains are going to agree that the longest chain is the one that they're going to go with, so long as it matches up with 51% of the rest of the network. This means that if you have the longest chain and 51% of the rest of network, you can do what's called a fork in the network and bring the network onto your now longest chain.

Scalability

  • A block only has so much block space and the nodes can only add so many transactions, so when a lot of people want to use a blockchain, the gas price skyrockets

Sharding

  • A blockchain of blockchains

Layer 1:

  • Base layer blockchain implementation

Layer 2:

  • Any application built on top of a layer 2

Recap

  • ETH and BTC are Proof Of Work
  • ETH 2.0 will be Proof of Stake
  • PoW & PoS are sybil resistance mechanisms
  • The bigger the blockchain, the more secure
  • Consensus is how blockchains decide whtat the state of the chain is
  • Sharding and rollups are scalability solutions
  • Only so many transactions can fit into a block
  • Gas prices are how much it costs to perform exectuions on-chain

Lesson 12: Upgrades

Proxy Terminology:

  1. The Implementation Contract
    • Which has all our code of our protocol. When we upgrade, we lauch a brand new implementation contract.
  2. The proxy contract
    • Which points to which implementation is the "correct" one, and routes everyone's function calls to that contract.
  3. The user
    • They make calls to the proxy
  4. The admin
    • This is the user (or group of users/voters) who upgrade to new implementation contracts.

Transparent Proxy Pattern

  • Admins can't call implementation contract functions
    • Admin functions are functions that govern the upgrades
  • Users still powerless on admin functions
  • Admin functions are functions that govern the upgrades
  • Admin functions are located in the proxy contract

Universal Upgradeable Proxies

AdminOuly Upgrade functions are in the implementation contracts instead of the proxy

Diamond Pattern

Allows for multiple implementation contracts

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract SimpleStorage {
// this will get initialized to 0!
uint256 public favoriteNumber;
struct People {
uint256 favoriteNumber;
string name;
}
People public person = People({favoriteNumber: 2, name: "Patrick"});
People[] public people;
// Mappings: A dictionary like data structure, with 1 value per key
mapping(string => uint256) public nameToFavoriteNumber;
function store(uint256 _favoriteNumber) public {
favoriteNumber = _favoriteNumber;
}
// view and pure are non-state changing functions
function retrieve() public view returns(uint256) {
return favoriteNumber;
}
// Memory: Data will only be stored during the execution of the function
function addPerson(string memory _name, uint256 _favoriteNumber) public {
people.push(People(_favoriteNumber, _name));
nameToFavoriteNumber[_name] = _favoriteNumber;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "./SimpleStorage.sol";
contract StorageFactory is SimpleStorage {
SimpleStorage[] public simpleStorageArray;
function createSimpleStorageContract() public {
SimpleStorage simpleStorage = new SimpleStorage();
simpleStorageArray.push(simpleStorage);
}
function sfStore(uint256 _simpleStorageIndex, uint256 _simpleStorageNumber) public {
// Address
// ABI = Application Binary Interface
SimpleStorage(address(simpleStorageArray[_simpleStorageIndex])).store(_simpleStorageNumber);
}
function sfGet(uint256 _simpleStorageIndex) public view returns (uint256) {
return SimpleStorage(address(simpleStorageArray[_simpleStorageIndex])).retrieve();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment