1/104
Looks like no tags are added yet.
Name | Mastery | Learn | Test | Matching | Spaced |
|---|
No study sessions yet.
Characteristics of Bitcoin Script
stack-based, simple isntruction set, non-Turing complete, deterministic
Pay-to-Public-Key-Hash (P2PKH)
single signature spending requiring a private key
Multi-signature (Multisig)
Requires M out of N signatures for shared custody/governance
Pay-to-Script-Hash (P2SH)
Complex conditions through referencing a script hash
Zero-Knowledge proofs
verifies transaction without revealing underlying data
Proof of work
get reward through computing valid nonce value
Halving of block reward
Starting in 2008, starts at 50 btc, divides by half every 4 years. Currently at 3.125
Difficulty Adjustment Alg
every 2016 blocks (2 weeks at 10-minute intervals), maximum 4x change per adjustment
UTXO Model
stateless, new address for each transaction, high parallelization, limited scripting, simple
Account Model
maintains account balances, reused addresses for transactions, limited parallelization, full programmability, complex
Externally Owned Accounts (EOAs)
controlled by private keys, initiates transactions, no code execution capabilities, used by human users and wallets, has nonce and balance
Contract Accounts
controlled by smart contract code, cannot initiate transactions, only responds to calls, contains executable bytecodes, has storage for persistent data
Nonce
for EOA, transaction counter preventing replay attacks
for contracts, number of contracts created
Balance
amount of Ether (in wei) owned by account, contracts can hold Ether
CodeHash
hash of the account’s code, points to executable bytecode, only for contracts
StorageRoot
root hash of the account’s storage trie, contains persistent data for smart contracts
Transfer Ether
sends ETH from one account to another
Call Contract Functions
executes code in existing smart contracts
Deploy Contracts
create new smart contracts on the network
to (transaction field)
Destination address or recipient
value (transaction field)
amount of ether to transfer
data (transaction field)
contract bytecode or function call data
gasLimit (transaction field)
maximum gas willing to spend
maxFeePerGas (transaction field)
maximum total fee per gas unit
maxPriorityFeePerGas (transaction field)
tip to minors for priority inclusion
Simple Transfer
to: recipient address
value: ETH amount
data: empty
Contract Call
to: contract address
value: ETH (optional)
data: function call
Contract Deployment
to: empty (null)
value: ETH (optional)
data: bytecode
Upfront payment of gas
gasLimit * maxFeePerGas
Common gas costs
basic operations (add, mul, etc.): 3-5 gas
memory operations: 3-200 gas
storage write: 20000 gas
contract creation: 32000 gas
Total Fee
GasUsed * (BaseFee + PriorityFee)
Base Fee
burned by admin to reduce ETH supply and prevent inflation
Priority Fee (Tip)
user-set tip to incentivize minors/validators to include the transaction quickly
Stack
LIFO with maximum of 1024 items, each item is max 256-bits
Memory
temporary byte-addressed storage that expands dynamically during execution, cleared after each call completes
Calldata
read-only input bytes passed to contract during transaction or call, contains function identifiers and encoded parameters, must be loaded onto stack for processing
Storage
persistent key value map from 256 bit keys to 256 bit values, survives after the call finishes, all slots initially zero
PUSH(1-16)
adds value to ith spot
DUP(1-16)
duplicates ith value to top
SWAP(1-16)
swaps top value with ith value after it
POP
removes top item
Arithmetic OPcodes (add, sub, mul, div, mod, addmod, mulmod)
256-bit modular arithmetic operations wraps at 2^256 on top two values of stack
Comparison opcodes (LT, GT, EQ, ISZERO)
compares top two values and produces boolean results
Control Flow OPcodes (JUMP, JUMPI, JUMPDEST, REVERT, STOP)
implements conditional and unconditional branching, JUMPDEST marks valid targets
Return OPcodes (RETURN, REVERT)
halts execution and return data (RETURN) or revert state changes (REVERT)
memory, storage, calldata opcodes (mload, mstore, mstore8, sload, sstore, calldataload, calldatasize, calldatacopy)
read and writes to top of stack, store expects key at top, value at 2nd, copy expects destoffset, offset, length
PUSH, DUP, SWAP cost
3 gas
POP cost
2 gas
ADD, SUB, MUL cost
3-5 gas
DIV, MOD cost
5 gas
LT, GT, EQ cost
3 gas
MLOAD, MSTORE cost
3 gas + expansion
SLOAD (warm) cost
100 gas
SLOAD (cold) cost
2100 gas
SSTORE (warm) cost
2900 gas
SSTORE (cold, new) cost
22100 gas
JUMP, JUMPI cost
8 gas
CALL cost
100+ gas (base)
Cold Access
first time accessing a storage slot in a transaction, first time calling a contract address, very high costs, compensates for loading data from disk
Warm Access
subsequent access to same slot/address, data already cached in memory, lower gas costs (than cold access), rewards batching operations
Read Batching
batch multiple reads from the same storage slot to reduce gas cost by turning cold reads into warm reads
Write Batching
accumulate changes in memory, commit once to storage, minimizes number of SSTORE operations
Cold to warm cost ratio
7.6x
why solidity
bridge to EVM bytecode
solodity source code > compiler translation > bytecode > evm execution
solidity enables the following 3 core capabilities which make ethereum programmable
persistent state management across transactions
programmatic rules that execute automatically
secure value transfer without intermediaries
how is solidity designed with blockchain constraints in mind
determnism
transparency
cost-awareness
what is a smart contract
combo of executable bytecode and persistent data stored at a specific blockchain address
what happens when a smart contract is deployed to the blockchain
bytecode becomes immutable
every interaction with it is transparent and recorded on the blockchain for anyone to audit
its state is persistently stored on the blockchain
how does persistent storage for smart contract states work
state variables are stored in the contract’s dedicated storage root within the Ethereum state trie and is maintained across blocks
describe the proxy pattern where developers can implement upgradability
while the code is immutable, you can use delegatecall to route execution to new logic contracts while preserving the original storage
3 essential components of the standard structure for a Solidity contract
SPDX License Identifier (software license)
Pragma directive (what compiler versions that can compile the code)
Contract block (main container for smart contract code)
example:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
contract SimpleStorage {
// state variables and functions here
}
state variables
stored permanently in blockchain. state maintained across all transactions
cheap to read on chain
very expensive to write
free to read off-chain
public keyword automatically generates a getter function (better transparency)
size of each storage slot
32 bytes, 256 bits
what are the different data locations
storage:
persistent
can read/write
high cost (5k-20k gas per write)
ex: state vars, permanent data
memory:
temporary during function call
mutable within function
low cost (3 gas per word)
ex: local variables, function parameters
calldata:
temporary during external call
read-only
lowest cost (0 copy overhead)
ex: external function inputs, the data field when someone calls a function on your contract, similar to passing by reference?
copy vs reference
storage to memory copies the data in temporary memory and costs high gas
storage reference creates pointer to on-chain data and is more efficient for updates
calldata has no copy.
ex:
function setAge(uint256 newAge) public {
// Creates a storage reference - modifies on-chain state
Profile storage ref = profiles[msg.sender];
ref.age = newAge;
// Creates a memory copy - changes lost after function ends
Profile memory copy = profiles[msg.sender];
copy.age = newAge; // This change is NOT persisted!
}
storage/memory/calldata best practices
storage reference to modify state variables
memory for temporary computations
calldata for external function parameters (especially large arrays)
value vs reference types
value types (copied by value, stored directly in their location)
uint256 (matches EVM native 256 bit word size, most gas-efficient for most operations)
uint8
bool
address (160 bits, 20 byte; used to identify both user and contract accounts)
reference types (passed by reference)
structs
arrays (also strings)
mapping (O(1) key-value lookup but non-iterable (can’t list all keys))
execution context
transactions execute within a context that has info about the caller, transaction, and current blockchain state
solodity shows context with global variables:
msg.sender (address which directly called the current function. used for access control. remains the original caller, not intermediate contract, for delegatecall)
msg.value (amount of wei (1 ether = 10^18 wei) sent with transaction. only accessible in payable functions)
block.timestamp (unix timestamp of current block used for implementing deadlines and time-based logic. miners can manipulate +-15 seconds so not good for precise timing)
function visibility specifiers
modify who can call a function and how
internal:
only callable within contract or derived contracts
helper functions, code reuse with inheritance
external:
only callable from other contracts or EOAs (externally owned accounts)
more gas efficient for functions with large calldata parameters
public
callable from anywhere (both internal and external)
default
private
only callable within defining contract
sensitive helper functions, shouldn’t be inherited
function mutability and payability modifiers
default(modifying)
can read/write state variables
view
can read state but not modify
free when called externally via RPC (off-chain)
pure
cannot read or write
math only
also free when called externally
payable
special modifier for function, address, or constructor to be able to recieve Ether
required for any function where msg.value>0
modifiers and errors
modifiers are reusable code blocks that execute before or after a function.
use require() to validate. if condition is false, transaction reverts, state changes undone, and unused gas is refunded
revert() for manual rollbacks
ex:
modifier onlyOwner() {
require(
msg.sender == owner,
"caller is not owner"
);
_; // Function body executes here
}
function withdraw() public onlyOwner {
// This function can only be called by owner
// The modifier check runs first
}withdraw pattern
checks-effects-interactions principle to prevent reentrancy attacks
always update state before transferring ether
validate preconditions > update state variables > make external calls last
transfer Ether with the call() function
recieve and fallback functions
special for handling ether transfers and unknown function calls
no function keyword
keep simple, limited 2300 gas when called via transfer or send
receive()
triggered when someone sends Ether with no function selector (plain transfer)
must be external payable and no parameters/return
fallback()
triggers when function doesn’t exist or Ether is sent without a receive() function
can be payable or non-payable
how to build modula defi-scale systems beyond single-contract logic
best practices
inheritance - reuse code and create policy layers
events - connect on and off-chain systems, transparency
libraries+guards - enable safe code reuse. use nonReentrant to protect against reentrancy attacks and value transfers
interfaces - build protocol composability. cross-protocol calls
avoid loops over user lists - can exceed gas limits
fork-test mainnet integrations - test on real protocol state before deployment
why inheritance
encapsulate reusable behavior (ownable, erc20)
define clear hierarchies
reduce duplication, redundant code
Ownable
inherit from Ownable base contract which has modifier that checks only the owner can access the function
inheritance keywords
virtual - allow override
override - replace parent implementation
super - extend, not rewrite (use parent’s implementation)
why events
smart contracts ahve no way to proactively notify external systems of state changes
emit events to create on-chain logs that are cheap and queryable
use for frontend updates, indexers, analytics dashboards, etc
always emit after state change. ensure events reflect actual final state to maintain data integrity
events example
event Deposit(address from, uint amount);
function deposit() external payable {
emit Deposit(msg.sender, msg.value);
}vault.on("Deposit", (from, amount) => {
console.log(`${from} deposited ${ethers.formatEther(amount)} ETH`);
});why libraries
reuse common logic with stateless helper functions
cleaner than inheritance. don’t add to contract size
trusted
examples:
SafeMath - prevent overflow
ReentrancyGuard - nonReentrant modifier for mutex, atomic functions
why composability and interfaces
defi need protocols calling protocols
cross-protocol interactions use interfaces, not inheritance
why security patterns matter
3 core defensive patterns
70% defi losses from bugs
checks-effects-interactions - validate, update, call
reentrancy guard - lock critical sections with mutex
pull over push - let users withdraw funds rather than pushing to them (use msg.sender instead of a separate address)
misc security good practices
access control
role-based access
fail fast with require+clear messages
code quality
lock compiler for overflow checks
use interfaces instead of hard-coded addresses
constant/immutable for config values
transparency
emit events for critical acions
document state-changing functions
testing
static analysis with slither/mythril
foundry fuzz testing
test edge cases and failure modes
what is an escrow contract
an escrow holds a payer’s funds until they’re released to the payee or decided by an arbiter
constructor: payer initializes contract with payer, payee, arbiter, deadline, and funds
withdraw: allows address with credited balance (payee) to pull funds from the contract once approved/credited
release: called by payer to mark the deal as resolved and credit the payee
resolve: called by arbiter to choose a winner and credit either payee or payer (refund)
escrow contract design patterns
pull-over-push
checks-effects-interactions
single withdrawal path (all transfers go through withdraw function)
what is a voting/governor contract
governor contract lets proposers suggest, voters decide, and approved actions execute after a timelock
allow stakeholders of a token to propose, vote on, and execute changes
constructor: admin initializes governor with timelock delay, quorum, and contract owner
propose: proposer creates new proposal defining target, value, calldata, and voting window
castVote: records a voter’s support or opposition using a snapshot of their voting power from a past block
queue: (done by off-chain executor) moves a passed proposal into the timelock queue and sets its earliest execution time
execute: (done by off-chain executor) executes the approved and queued proposal after delay expires
voting/governor contract design patterns
snapshot voting - fix voting power at past block to prevent manipulation
timelock delay - wait after passing for users can review/prep
whitelisted auction - only call pre-approved targets
auditability - every step is on-chain and verifiable
event driven off-chain trigger - bots/users listen to events and trigger execution
what is a commit-reveal auction
lets bidders first hide bids with a hash, and then reveal them later for fair comparison
constructor: seller initializes the auction by setting the seller, phase, and time deadlines for commit and reveal periods
commit: bidders submit a hashed bid witha. deposit during the commit phase
reveal: bidders reveal their real bid and salt for verification, updating the highest bid if valid
withdrawal: handles payouts: seller gets payment, winner gets change, others get refunds
auction contract design patterns
state machine with time-based transitions - enforces commit > reveal > finalized by timestamps so actions run in right order
commit-reveal - commit a hidden bid hash, reveal later to prove it
one-time commitment - clear the commitment after reveal to prevent double reveals or reuse