# Eridian Docs

Public documentation by Eridian.

> You'll always feel "late". But opportunity only lies ahead ➡️

<div align="left"><figure><img src="/files/0GSYZkV8YIOdQzDaEnlG" alt="" width="563"><figcaption></figcaption></figure></div>


# Ethereum Dev


# Infrastructure


# Hardware

Notes on my hardware.

<figure><img src="/files/uViEicnXZzRTQ3BXlcrW" alt="Eridian NUC"><figcaption><p>Eridian Hardware - NUC</p></figcaption></figure>


# Ethereum Clients

Notes on how to install, use and maintain multiple Ethereum validator clients.


# Execution Clients

{% content-ref url="/pages/G0JCzPCPOmtNoHFY9SPW" %}
[Geth](/ethereum-dev/infrastructure/client-software/execution-clients/geth)
{% endcontent-ref %}

{% content-ref url="/pages/vnnE8Axvk3YVm3nobgvL" %}
[Erigon](/ethereum-dev/infrastructure/client-software/execution-clients/erigon)
{% endcontent-ref %}

{% content-ref url="/pages/Ui4PZMWu71UFe7QaVqFy" %}
[Besu](/ethereum-dev/infrastructure/client-software/execution-clients/besu)
{% endcontent-ref %}

## Process - Changing Clients

1. Stop old client.
2. Disable old client.
3. Delete old client data.
4. Enable new client.
5. Start new client.

## UFW Config

Configure the firewall.

{% code title="Execution Clients" %}

```bash
EXECUTION_P2P_PORT=        # Default: 30303
EXECUTION_WS_PORT=         # Default: 8546
EXECUTION_METRICS_PORT=    # Default: 6060
EXECUTION_RPC_PORT=        # Default: 8545

sudo ufw allow ${EXECUTION_P2P_PORT} comment 'Allow Execution P2P in'
sudo ufw allow ${EXECUTION_WS_PORT} comment 'Allow Execution WS in'
sudo ufw allow ${EXECUTION_METRICS_PORT} comment 'Allow Execution Metrics in'
sudo ufw allow ${EXECUTION_RPC_PORT} comment 'Allow Execution RPC Port in'
```

{% endcode %}

## Create JWT Secret

This is now shared between all clients on the same machine.

```bash
sudo openssl rand -hex 32 | tr -d "\n" > "/tmp/jwtsecret"
sudo mv /tmp/jwtsecret /var/lib/
sudo chmod +r /var/lib/jwtsecret
```

## Execution Service Environment Variables

```bash
sudo vim /etc/default/execution-variables.env
```

{% code fullWidth="false" %}

```ini
NETWORK=                               # E.g. mainnet or holesky
EXECUTION_P2P_PORT=                    # Default: 30303
EXECUTION_MAX_PEERS=                   # Default: 50
EXECUTION_WS_ADDR=                     # e.g. 0.0.0.0
EXECUTION_WS_PORT=                     # Default: 8546
EXECUTION_RPC_ADDR=                    # e.g. 0.0.0.0
EXECUTION_RPC_PORT=                    # Default: 8545
EXECUTION_METRICS_ADDR=                # e.g. 0.0.0.0
EXECUTION_METRICS_PORT=                # Avoid 6060 clash with pprof: 6061
NGINX_PROXY_EXECUTION_METRICS_PORT=    # Unified metrics port e.g. 6062
```

{% endcode %}


# Geth

Notes on how to install, use and maintain a Geth client.

{% content-ref url="/pages/7yZWWEqezJHKogTqVDEm" %}
[Installation](/ethereum-dev/infrastructure/client-software/execution-clients/geth/installation)
{% endcontent-ref %}

{% content-ref url="/pages/URejy0cUUIO7qnpTxqWq" %}
[Useful Commands](/ethereum-dev/infrastructure/client-software/execution-clients/geth/useful-commands)
{% endcontent-ref %}

{% content-ref url="/pages/hJqEZB6MyKhFgWJvsEUb" %}
[Maintenance](/ethereum-dev/infrastructure/client-software/execution-clients/geth/maintenance)
{% endcontent-ref %}


# Installation

Geth client installation guide.

### Create Aliases

These aliases make interacting with `Geth` on the command line easier.

{% code fullWidth="true" %}

```bash
echo "alias geth-log='journalctl -f -u geth.service -o cat | ccze -A'" >> ~/.bashrc
echo "alias geth-start='sudo systemctl start geth.service'" >> ~/.bashrc
echo "alias geth-stop='sudo systemctl stop geth.service'" >> ~/.bashrc
echo "alias geth-restart='sudo systemctl restart geth.service'" >> ~/.bashrc
echo "alias geth-status='sudo systemctl status geth.service'" >> ~/.bashrc
echo "alias geth-version='sudo /usr/local/bin/geth --version'" >> ~/.bashrc
echo "alias geth-config='sudo vim /etc/systemd/system/geth.service'" >> ~/.bashrc
echo "alias geth-enable='sudo systemctl enable geth.service'" >> ~/.bashrc
echo "alias geth-disable='sudo systemctl disable geth.service'" >> ~/.bashrc
echo "alias geth-delete-data='sudo rm -rf /var/lib/goethereum/geth'" >> ~/.bashrc
echo "alias geth-update='~/geth-update.sh'" >> ~/.bashrc

echo "alias geth-attach='sudo geth attach --preload ~/geth-console-script.js /var/lib/goethereum/geth.ipc'" >> ~/.bashrc
echo "alias geth-blockNumber='sudo geth --exec \"eth.blockNumber\" attach /var/lib/goethereum/geth.ipc'" >> ~/.bashrc
echo "alias geth-peerCount='sudo geth --exec \"net.peerCount\" attach /var/lib/goethereum/geth.ipc'" >> ~/.bashrc
echo "alias geth-nodeInfo='sudo geth --exec \"admin.nodeInfo\" attach /var/lib/goethereum/geth.ipc'" >> ~/.bashrc

source ~/.bashrc
```

{% endcode %}

### Firewall Configuration

Configure the firewall using generic Execution client UFW settings:[Execution Clients](/ethereum-dev/infrastructure/client-software/execution-clients#ufw)

### Go - Install

Find the latest version of `Go` here: <https://go.dev/doc/install>

```bash
GO_LATEST_VERSION=    # Add the latest Go version here

cd ~/
wget https://go.dev/dl/go${GO_LATEST_VERSION}.linux-amd64.tar.gz
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go${GO_LATEST_VERSION}.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
echo 'PATH="$PATH:/usr/local/go/bin"' >> ~/.profile
```

### Geth - Install

Build the latest version of `Geth`.

```bash
GETH_VERSION_COMMIT_HASH=        # e.g.3f907d6

cd ~
git clone https://github.com/ethereum/go-ethereum.git
cd go-ethereum
git checkout ${GETH_VERSION_COMMIT_HASH}
make geth
```

Move the compiled `Geth` build to a new directory.

```bash
sudo cp ~/go-ethereum/build/bin/geth /usr/local/bin
```

Create `Geth` user and directory.

```bash
sudo useradd --no-create-home --shell /bin/false goeth
sudo mkdir -p /var/lib/goethereum
```

JWT Secret is now shared between all clients on the same machine:[Execution Clients](/ethereum-dev/infrastructure/client-software/execution-clients#create-jwt-secret)

### Geth - Configure Service

Set permissions.

```bash
sudo chown -R goeth:goeth /var/lib/goethereum
```

Configure [Execution Clients](/ethereum-dev/infrastructure/client-software/execution-clients#execution-service-environment-variables).

Configure `Geth` service using the command line flags.

```bash
sudo vim /etc/systemd/system/geth.service
```

{% tabs %}
{% tab title="/etc/systemd/system/geth.service" %}
{% code title="/etc/systemd/system/geth.service" %}

```bash
[Unit]
Description=Go Ethereum Client (Geth) - Execution Node
After=network.target
Wants=network.target

[Service]
User=goeth
Group=goeth
Type=simple
Restart=always
RestartSec=5
TimeoutStopSec=1200

EnvironmentFile=/etc/default/execution-variables.env

ExecStart=/usr/local/bin/geth \
    --${NETWORK} \
    --syncmode=snap \
    --port ${EXECUTION_P2P_PORT} \
    --discovery.port ${EXECUTION_P2P_PORT} \
    --datadir /var/lib/goethereum \
    \
    --pprof \
    --metrics \
    --metrics.expensive \
    --metrics.addr ${EXECUTION_METRICS_ADDR} \
    --metrics.port ${EXECUTION_METRICS_PORT} \
    \
    --authrpc.jwtsecret=/var/lib/jwtsecret \
    --maxpeers ${EXECUTION_MAX_PEERS} \
    \
    --ws \
    --ws.origins '*' \
    --ws.port ${EXECUTION_WS_PORT} \
    --ws.addr ${EXECUTION_WS_ADDR} \
    \
    --http \
    --http.api "db,eth,net,engine,rpc,web3" \
    --http.vhosts "*" \
    --http.corsdomain "*" \
    --http.addr ${EXECUTION_RPC_ADDR} \
    --http.port ${EXECUTION_RPC_PORT}

[Install]
WantedBy=default.target
```

{% endcode %}
{% endtab %}

{% tab title="Geth Flags Explained" %}

<table data-header-hidden><thead><tr><th width="294">Flag</th><th>Description</th></tr></thead><tbody><tr><td><code>/usr/local/bin/geth</code></td><td>Starts Geth.</td></tr><tr><td><code>--mainnet</code></td><td>Specifies mainnet as the target network.</td></tr><tr><td><code>--syncmode</code></td><td><ul><li><code>full</code> very/impossibly slow on Mainnet due to Shanghai DDOS attacks.</li><li><code>fast</code> used to be the best option, but is now slower than snap.</li><li><code>snap</code> the current fastest way to sync.</li></ul></td></tr><tr><td><code>--port</code></td><td>Network listening port (TCP).</td></tr><tr><td><code>--discovery.port</code></td><td>UDP port for P2P discovery.</td></tr><tr><td><code>--http</code></td><td>Enable the HTTP-RPC server.</td></tr><tr><td><code>--datadir</code></td><td>Data directory for the databases and keystore.</td></tr><tr><td><code>--metrics</code></td><td>Enable metrics collection and reporting.</td></tr><tr><td><code>--metrics.expensive</code></td><td>Enable expensive metrics collection and reporting.</td></tr><tr><td><code>--pprof</code></td><td><p>Enable the pprof HTTP server.</p><p>Required for metrics to work properly.</p></td></tr><tr><td><code>--http.api</code></td><td>API's offered over the HTTP-RPC interface.</td></tr><tr><td><code>--authrpc.jwtsecret</code></td><td></td></tr><tr><td><code>--maxpeers</code></td><td><p>Maximum number of network peers.</p><ul><li>Network disabled if set to 0.</li><li>Default: 50.</li></ul></td></tr><tr><td><code>--cache</code></td><td><p>Megabytes of memory allocated to internal caching.</p><ul><li>Default = 4096 mainnet full node and 128 light mode.</li></ul></td></tr><tr><td><code>--bootnodes</code></td><td><p>Comma separated enode URLs for P2P discovery bootstrap.</p><ul><li><a href="https://github.com/ethereum/go-ethereum/blob/master/params/bootnodes.go">https://github.com/ethereum/go-ethereum/blob/master/params/bootnodes.go</a></li></ul></td></tr></tbody></table>
{% endtab %}
{% endtabs %}

Start the service and check it's working as expected.

### Geth - Command Aliases

```bash
daemon-reload   # Reload any changes made to the geth.service
geth-enable     # Enable the geth.service
geth-start      # Start the geth.service
geth-status     # View the status of the geth.service

geth-log        # View the geth.service logs
```

### Geth - Update Scripts

Create `Geth` update script.

```bash
vim ~/geth-update.sh
```

{% code title="\~/geth-update.sh" %}

```bash
#!/bin/bash
set -e

while true; do
    read -p "Are you sure you want to update Geth? (Y/N) " yn
    case $yn in
        [Yy]* ) break;;
        [Nn]* ) exit;;
        * ) echo "Please answer Y or N.";;
    esac
done

cd ~/go-ethereum

read -p "Enter the commit hash you want to checkout: " commit_hash

git fetch
git checkout $commit_hash

echo
echo "**************"
echo "Making Geth..."
echo "**************"
make geth

# Check if geth.service is running
service_was_running=0
if sudo systemctl is-active --quiet geth.service; then
    service_was_running=1
    echo "****************"
    echo "Stopping Geth..."
    sudo systemctl stop geth.service
fi

echo "Replacing previous version..."
sudo rm -rf /usr/local/bin/geth
sudo cp ~/go-ethereum/build/bin/geth /usr/local/bin

# Only start geth.service if it was running originally
if [ $service_was_running -eq 1 ]; then
    echo "Restarting Geth..."
    echo "******************"
    sudo systemctl start geth.service
fi
```

{% endcode %}

Make the script executable.

```bash
chmod u+x ~/geth-update.sh
```

### Geth - Configure JavaScript Console

Use `--preload` to load pre-written commands and functions stored in a script file.

```bash
vim ~/geth-console-script.js
```

{% code title="\~/geth-console-script.js" %}

```bash
function blockInfo() {
    var blockInfo;
    web3.eth.getBlock(eth.blockNumber, function(e, r) { blockInfo = r; });
    return blockInfo;
}
```

{% endcode %}

Check `Geth` details by attaching to the JavaScript console

```bash
geth-attach
```

`Geth` JavaScript console commands.

```bash
eth.syncing
net.peerCount
```


# Useful Commands

Notes on how to use a Geth Client.

{% hint style="info" %}
All of the alias commands have been defined as aliases in \~/`.bashrc when`installing Geth.
{% endhint %}

### geth.service

```bash
geth-log            # View the geth.service logs
geth-start          # Start the geth.service
geth-stop           # Stop the geth.service
geth-restart        # Restart the geth.service
geth-status         # View the status of the geth.service
geth-version        # Check the version of Geth in use
geth-enable         # Enable the geth.service
geth-disable        # Disable the geth.service
geth-delete-data    # Delete all Geth chain data

geth-config         # Open the /etc/systemd/system/geth.service in vim
daemon-reload       # Reload any changes made to the geth.service
```

### Geth Direct Queries

To make this easier, these commands can be executed directly from the command line without attaching the JS console.

```bash
geth-blockNumber
geth-peerCount
geth-nodeInfo
```

### Geth JavaScript Console

Attach to the `Geth` JavaScript console.

```bash
geth-attach
```

Console commands.

```javascript
eth.syncing                                            // Check if Geth is syncing
eth.blockNumber                                        // Show the current block number
eth.getTransaction("0x000...."                         // Get details of a specific transaction
eth.syncing.highestBlock - eth.syncing.currentBlock    // Distance remaining to sync
net.listening                                          // Report whether the Geth node is listening for inbound requests
net.peerCount                                          // Show number of active peers
admin.peers                                            // Show info about all peers
admin.peers[0]                                         // Show info about specific peer
admin.nodeInfo                                         // Show info about your own node
admin.peers.map((el) => el.network.inbound)            // You should see both true and false values meaning that your node is discoverable in the P2P network. If you’re seeing only false, you probably did not publicly expose the TCP and UDP port
blockInfo()                                            // Show information about the current block
blockInfo().totalDifficulty                            // Show the current block total difficulty
```

Exit the `Geth` JavaScript console.

```bash
exit
```

### Other Useful Commands

Checks `Geth` is running.

```bash
GETH_PORT=        # Default 8545

curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":67}' http://localhost:${GETH_PORT}
```

Check ports can be accessed.

```bash
PORTS_TO_CHECK=        # E.g. 30303,9000

curl https://eth2-client-port-checker.vercel.app/api/checker?ports=${PORTS_TO_CHECK}
```

Checks the validator status using the validator's public address.

```bash
VALIDATOR_HTTP_PORT=        # Lighthouse default: 5052
VALIDATOR_PUBLIC_KEY=       # E.g. 0x88426dd9c3d2bb71ad862a2e47d537304de528e88f5164f6db6ec423f1f7ed24d050c27ae4df45b37d2a4931fc820edf

curl -s http://127.0.0.1:${VALIDATOR_HTTP_PORT}/eth/v1/beacon/states/head/validators/${VALIDATOR_PUBLIC_KEY} |jq
```

Check validator status using a public endpoint in a browser.

```html
https://beaconstate.info/eth/v1/beacon/states/head/validators/<VALIDATOR_PUBLIC_KEY>
```

### Data Locations

`Geth` `chaindata` location.

```
/var/lib/goethereum/geth/chaindata
```


# Maintenance

Notes on how to maintain and update a Geth Client.

### Go - Update

Find the latest version of `Go` here: <https://go.dev/doc/install>

```bash
GO_LATEST_VERSION=    # Add the latest Go version here

cd ~/
wget https://go.dev/dl/go${GO_LATEST_VERSION}.linux-amd64.tar.gz
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go${GO_LATEST_VERSION}.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
echo 'PATH="$PATH:/usr/local/go/bin"' >> ~/.profile
```

### Geth - Update Client

```bash
geth-update
```

### Geth - Update geth.service

```bash
geth-stop
geth-config

# MAKE ANY CHANGES TO THE CONFIG

daemon-reload
geth-start
geth-status
```

### Geth - Rollback Chain to Previous Block Number

This was needed for a bug introduced in Geth v.1.10.22 that required a rollback to a previous block

Add `debug` flag to `--http.api`

```bash
geth-stop
geth-config

# Add "debug" to http.api
# --http.api="engine,eth,web3,net,debug"

daemon-reload
geth-start
geth-attach
```

In the `Geth` console set the new block head e.g. `debug.setHead("0xEAC1A8")`.

```javascript
debug.setHead("0x<BLOCK_NUMBER_IN_HEX>")
```

Once re-sync has been completed, go back and remove the `debug` flag from the `--http.api` argument.

### Geth - Resync after an Unexpected Shutdown

To avoid duplication these details can be found on the EthStaker Knowledge Base.

* [How to resync Geth](https://ethstaker.gitbook.io/ethstaker-knowledge-base/tutorials/resync-geth)

### Geth - Pruning

```bash
geth-stop

tmux new -s prune-geth
sudo /usr/local/bin/geth --datadir /var/lib/goethereum snapshot prune-state

exit
sudo chown -R goeth:goeth /var/lib/goethereum
geth-start
```


# Erigon

Notes on how to install, use and maintain an Erigon client.

{% content-ref url="/pages/3QkQJnNHaW2HdddKcVlY" %}
[Installation](/ethereum-dev/infrastructure/client-software/execution-clients/erigon/installation)
{% endcontent-ref %}

{% content-ref url="/pages/tSU09fjEkBKeKvjU2Hts" %}
[Useful Commands](/ethereum-dev/infrastructure/client-software/execution-clients/erigon/useful-commands)
{% endcontent-ref %}

{% content-ref url="/pages/GsvLP8UgU5bqeAUwTiQo" %}
[Maintenance](/ethereum-dev/infrastructure/client-software/execution-clients/erigon/maintenance)
{% endcontent-ref %}


# Installation

Erigon client installation guide.

### Create Aliases

These aliases make interacting with `Erigon` on the command line easier.

{% code fullWidth="true" %}

```bash
echo "alias erigon-log='journalctl -f -u erigon.service -o cat | ccze -A'" >> ~/.bashrc
echo "alias erigon-start='sudo systemctl start erigon.service'" >> ~/.bashrc
echo "alias erigon-stop='sudo systemctl stop erigon.service'" >> ~/.bashrc
echo "alias erigon-restart='sudo systemctl restart erigon.service'" >> ~/.bashrc
echo "alias erigon-status='sudo systemctl status erigon.service'" >> ~/.bashrc

echo "alias erigon-version='sudo /usr/local/bin/erigon --version'" >> ~/.bashrc
echo "alias erigon-config='sudo vim /etc/systemd/system/erigon.service'" >> ~/.bashrc

echo "alias erigon-enable='sudo systemctl enable erigon.service'" >> ~/.bashrc
echo "alias erigon-disable='sudo systemctl disable erigon.service'" >> ~/.bashrc

echo "alias erigon-delete-data='sudo rm -rf /var/lib/goethereum/erigon'" >> ~/.bashrc
echo "alias erigon-update='~/erigon-update.sh'" >> ~/.bashrc

source ~/.bashrc
```

{% endcode %}

### Firewall Configuration

Configure the firewall using generic Execution client UFW settings:[Execution Clients](/ethereum-dev/infrastructure/client-software/execution-clients#ufw)

### Erigon - Install

Build the latest version of `Erigon`.

```bash
ERIGON_VERSION_COMMIT_HASH=        # e.g.3f907d6

cd ~
git clone --recurse-submodules https://github.com/ledgerwatch/erigon.git
cd erigon
git checkout ${ERIGON_VERSION_COMMIT_HASH}
make erigon
```

Move the compiled `Erigon` build to a new directory.

```bash
sudo cp ~/erigon/build/bin/erigon /usr/local/bin
```

Create `Erigon` user and directory.

```bash
sudo useradd --no-create-home --shell /bin/false erigon
sudo mkdir -p /var/lib/erigon
```

JWT Secret is now shared between all clients on the same machine:[Execution Clients](/ethereum-dev/infrastructure/client-software/execution-clients#create-jwt-secret)

### Erigon - Configure Service

Set permissions.

```bash
sudo chown -R erigon:erigon /var/lib/erigon
```

Configure [Execution Clients](/ethereum-dev/infrastructure/client-software/execution-clients#execution-service-environment-variables).

Configure `Erigon` service using the command line flags.

```bash
sudo vim /etc/systemd/system/erigon.service
```

{% tabs %}
{% tab title="/etc/systemd/system/erigon.service" %}
{% code title="/etc/systemd/system/erigon.service" %}

```bash
[Unit]
Description=Erigon Ethereum Client - Execution Node
After=network.target
Wants=network.target

[Service]
User=erigon
Group=erigon
Type=simple
Restart=always
RestartSec=5
TimeoutStopSec=1200

EnvironmentFile=/etc/default/execution-variables.env

ExecStart=/usr/local/bin/erigon \
    --internalcl \
    --chain ${NETWORK} \
    --port ${EXECUTION_P2P_PORT} \
    --datadir /var/lib/erigon \
    \
    --pprof \
    --metrics \
    --metrics.addr ${EXECUTION_METRICS_ADDR} \
    --metrics.port ${EXECUTION_METRICS_PORT} \
    \
    --authrpc.jwtsecret=/var/lib/jwtsecret \
    --maxpeers ${EXECUTION_MAX_PEERS} \
    \
    --ws \
    --ws.port ${EXECUTION_WS_PORT} \
    \
    --http \
    --http.api "eth,erigon,engine" \
    --http.vhosts "*" \
    --http.corsdomain "*" \
    --http.addr ${EXECUTION_RPC_ADDR} \
    --http.port ${EXECUTION_RPC_PORT} \
    \
    --torrent.download.rate=512mb

[Install]
WantedBy=default.target
```

{% endcode %}
{% endtab %}
{% endtabs %}

Start the service and check it's working as expected.

### Erigon - Command Aliases

```bash
daemon-reload     # Reload any changes made to the erigon.service
erigon-enable     # Enable the erigon.service
erigon-start      # Start the erigon.service
erigon-status     # View the status of the erigon.service

erigon-log        # View the erigon.service logs
```

### Erigon - Update Scripts

Create `Erigon` update script.

```bash
vim ~/erigon-update.sh
```

{% code title="\~/erigon-update.sh" %}

```bash
#!/bin/bash
set -e

while true; do
    read -p "Are you sure you want to update Erigon? (Y/N) " yn
    case $yn in
        [Yy]* ) break;;
        [Nn]* ) exit;;
        * ) echo "Please answer Y or N.";;
    esac
done

cd ~/erigon

read -p "Enter the commit hash you want to checkout: " commit_hash

git fetch
git checkout $commit_hash

echo
echo "****************"
echo "Making Erigon..."
echo "****************"
make erigon

# Check if erigon.service is running
service_was_running=0
if sudo systemctl is-active --quiet erigon.service; then
    service_was_running=1
    echo "******************"
    echo "Stopping Erigon..."
    sudo systemctl stop erigon.service
fi

echo "Replacing previous version..."
sudo rm -rf /usr/local/bin/erigon
sudo cp ~/erigon/build/bin/erigon /usr/local/bin

# Only start erigon.service if it was running originally
if [ $service_was_running -eq 1 ]; then
    echo "Restarting Erigon..."
    echo "********************"
    sudo systemctl start erigon.service
fi
```

{% endcode %}

Make the script executable.

```bash
chmod u+x ~/erigon-update.sh
```


# Useful Commands

Notes on how to use a Geth Client.

{% hint style="info" %}
All of the alias commands have been defined as aliases in \~/`.bashrc when`installing Erigon.
{% endhint %}

### erigon.service

```bash
erigon-log            # View the erigon.service logs
erigon-start          # Start the erigon.service
erigon-stop           # Stop the erigon.service
erigon-restart        # Restart the erigon.service
erigon-status         # View the status of the erigon.service
erigon-version        # Check the version of Erigon in use
erigon-enable         # Enable the erigon.service
erigon-disable        # Disable the erigon.service
erigon-delete-data    # Delete all Erigon chain data

erigon-config         # Open the /etc/systemd/system/erigon.service in vim
daemon-reload         # Reload any changes made to the erigon.service
```

### Data Locations

`Erigon` `chaindata` location.

```
/var/lib/erigon/chaindata
```


# Maintenance

Notes on how to maintain and update a Geth Client.

### Go - Update

Find the latest version of `Go` here: <https://go.dev/doc/install>

```bash
GO_LATEST_VERSION=    # Add the latest Go version here

cd ~/
wget https://go.dev/dl/go${GO_LATEST_VERSION}.linux-amd64.tar.gz
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go${GO_LATEST_VERSION}.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
echo 'PATH="$PATH:/usr/local/go/bin"' >> ~/.profile
```

### Erigon - Update Client

```bash
erigon-update
```

### Erigon - Update erigon.service

```bash
erigon-stop
erigon-config

# MAKE ANY CHANGES TO THE CONFIG

daemon-reload
erigon-start
erigon-status
```


# Besu

Notes on how to install, use and maintain a Besu client.

{% content-ref url="/pages/yPXFZa4x89KA26BgPyFd" %}
[Installation](/ethereum-dev/infrastructure/client-software/execution-clients/besu/installation)
{% endcontent-ref %}

{% content-ref url="/pages/dq8jaFqOcZ3BZHiR7Oka" %}
[Useful Commands](/ethereum-dev/infrastructure/client-software/execution-clients/besu/useful-commands)
{% endcontent-ref %}

{% content-ref url="/pages/AfwkniatJIlqbgHuon2z" %}
[Maintenance](/ethereum-dev/infrastructure/client-software/execution-clients/besu/maintenance)
{% endcontent-ref %}


# Installation

Besu client installation guide.

### Create Aliases

These aliases make interacting with `Besu` on the command line easier.

{% code fullWidth="true" %}

```bash
echo "alias besu-log='journalctl -f -u besu.service -o cat | ccze -A'" >> ~/.bashrc
echo "alias besu-start='sudo systemctl start besu.service'" >> ~/.bashrc
echo "alias besu-stop='sudo systemctl stop besu.service'" >> ~/.bashrc
echo "alias besu-restart='sudo systemctl restart besu.service'" >> ~/.bashrc
echo "alias besu-status='sudo systemctl status besu.service'" >> ~/.bashrc
echo "alias besu-version='sudo /usr/local/bin/besu/bin/besu --version'" >> ~/.bashrc
echo "alias besu-config='sudo vim /etc/systemd/system/besu.service'" >> ~/.bashrc
echo "alias besu-enable='sudo systemctl enable besu.service'" >> ~/.bashrc
echo "alias besu-disable='sudo systemctl disable besu.service'" >> ~/.bashrc
echo "alias besu-delete-data='sudo rm -rf /var/lib/besu; sudo mkdir -p /var/lib/besu; sudo chown -R besu:besu /var/lib/besu'" >> ~/.bashrc
echo "alias besu-update='~/besu-update.sh'" >> ~/.bashrc

source ~/.bashrc
```

{% endcode %}

### Firewall Configuration

Configure the firewall using generic Execution client UFW settings:[Execution Clients](/ethereum-dev/infrastructure/client-software/execution-clients#ufw)

### Dependency - Install Java

`Besu` requires version 17+ of Java: <https://besu.hyperledger.org/public-networks/get-started/install/binary-distribution#prerequisites-1>

```bash
sudo apt-get install openjdk-21-jre-headless openjdk-21-jdk -y

sudo apt-get install libsodium23 libnss3 -y
```

### Besu - Install

Build the latest version of `Besu`.

```bash
BESU_VERSION_COMMIT_HASH=        # e.g.3f907d6

cd ~
git clone --recursive https://github.com/hyperledger/besu
cd ~/besu
git checkout ${BESU_VERSION_COMMIT_HASH}
./gradlew build -x test
./gradlew clean installDist
```

Move the compiled `Besu` build to a new directory.

```bash
sudo cp -R ~/besu/build/install/besu /usr/local/bin
```

Check version.

```bash
/usr/local/bin/besu/bin/besu --version
```

Create `Besu` user and directory.

```bash
sudo useradd --no-create-home --shell /bin/false besu
sudo mkdir -p /var/lib/besu
```

JWT Secret is now shared between all clients on the same machine: [Execution Clients](/ethereum-dev/infrastructure/client-software/execution-clients#create-jwt-secret)

### Besu - Configure Service

Set permissions.

```bash
sudo chown -R besu:besu /var/lib/besu
```

Configure [Execution Clients](/ethereum-dev/infrastructure/client-software/execution-clients#execution-service-environment-variables).

Configure `Besu` service using the command line flags.

```bash
sudo vim /etc/systemd/system/besu.service
```

{% code title="/etc/systemd/system/besu.service" %}

```bash
[Unit]
Description=Besu Ethereum Client - Execution Node
After=network.target
Wants=network.target

[Service]
User=besu
Group=besu
Type=simple
Restart=always
RestartSec=5
TimeoutStopSec=1200

EnvironmentFile=/etc/default/execution-variables.env

ExecStart=/usr/local/bin/besu/bin/besu \
    --network=${NETWORK} \
    --sync-mode=SNAP \
    --engine-jwt-secret=/var/lib/jwtsecret \
    --data-path=/var/lib/besu \
    --data-storage-format=BONSAI \
    --p2p-port=${EXECUTION_P2P_PORT} \
    --max-peers=${EXECUTION_MAX_PEERS} \
    --engine-host-allowlist="*" \
    --host-allowlist="*" \
    \
    --metrics-enabled=true \
    --metrics-host=${EXECUTION_METRICS_ADDR} \
    --metrics-port=${EXECUTION_METRICS_PORT} \
    \
    --rpc-ws-enabled=true \
    --rpc-ws-api=ETH,NET,WEB3 \
    --rpc-ws-host=${EXECUTION_WS_ADDR} \
    --rpc-ws-port=${EXECUTION_WS_PORT} \
    \
    --rpc-http-enabled=true \
    --rpc-http-api=ETH,NET,WEB3 \
    --rpc-http-cors-origins="*" \
    --rpc-http-host=${EXECUTION_RPC_ADDR} \
    --rpc-http-port=${EXECUTION_RPC_PORT} \
    \
    --Xplugin-rocksdb-high-spec-enabled

[Install]
WantedBy=default.target
```

{% endcode %}

Start the service and check it's working as expected.

### Besu - Command Aliases

```bash
daemon-reload   # Reload any changes made to the besu.service
besu-enable     # Enable the besu.service
besu-start      # Start the besu.service
besu-status     # View the status of the besu.service

besu-log        # View the besu.service logs
```

### Besu - Update Scripts

Create `Besu` update script.

```bash
vim ~/besu-update.sh
```

{% code title="\~/besu-update.sh" %}

```bash
#!/bin/bash
set -e

while true; do
    read -p "Are you sure you want to update Besu? (Y/N) " yn
    case $yn in
        [Yy]* ) break;;
        [Nn]* ) exit;;
        * ) echo "Please answer Y or N.";;
    esac
done

read -p "Enter the commit hash you want to checkout: " commit_hash

# Delete existing besu directory to avoid commit mismatch errors
cd ~
sudo rm -rf besu
git clone --recursive https://github.com/hyperledger/besu
cd ~/besu
git checkout $commit_hash

echo
echo "**************"
echo "Making Besu..."
echo "**************"
./gradlew build -x test
./gradlew clean installDist

# Check if besu.service is running
service_was_running=0
if sudo systemctl is-active --quiet besu.service; then
    service_was_running=1
    echo "****************"
    echo "Stopping Besu..."
    sudo systemctl stop besu.service
fi

echo "Replacing previous version..."
sudo rm -rf /usr/local/bin/besu
sudo cp -R ~/besu/build/install/besu /usr/local/bin

# Only start besu.service if it was running originally
if [ $service_was_running -eq 1 ]; then
    echo "Restarting Besu..."
    echo "******************"
    sudo systemctl start besu.service
fi
```

{% endcode %}

Make the script executable.

```bash
chmod u+x ~/besu-update.sh
```


# Useful Commands

Notes on how to use a Besu Client.

{% hint style="info" %}
All of the alias commands have been defined as aliases in \~/`.bashrc when`installing Besu.
{% endhint %}

### geth.service

```bash
besu-log            # View the besu.service logs
besu-start          # Start the besu.service
besu-stop           # Stop the besu.service
besu-restart        # Restart the besu.service
besu-status         # View the status of the besu.service
besu-version        # Check the version of Besu in use
besu-enable         # Enable the besu.service
besu-disable        # Disable the besu.service
besu-delete-data    # Delete all Besu chain data

besu-config         # Open the /etc/systemd/system/geth.service in vim
daemon-reload       # Reload any changes made to the geth.service
```

### Other Useful Commands

Checks `Besu` is running.

```bash
BESU_PORT=        # Default 8545

curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":67}' http://localhost:${GETH_PORT}
```

Check ports can be accessed.

```bash
PORTS_TO_CHECK=        # E.g. 30303,9000

curl https://eth2-client-port-checker.vercel.app/api/checker?ports=${PORTS_TO_CHECK}
```

Checks the validator status using the validator's public address.

```bash
VALIDATOR_HTTP_PORT=        # Lighthouse default: 5052
VALIDATOR_PUBLIC_KEY=       # E.g. 0x88426dd9c3d2bb71ad862a2e47d537304de528e88f5164f6db6ec423f1f7ed24d050c27ae4df45b37d2a4931fc820edf

curl -s http://127.0.0.1:${VALIDATOR_HTTP_PORT}/eth/v1/beacon/states/head/validators/${VALIDATOR_PUBLIC_KEY} |jq
```

Check validator status using a public endpoint in a browser.

```html
https://beaconstate.info/eth/v1/beacon/states/head/validators/<VALIDATOR_PUBLIC_KEY>
```

### Data Locations

`Besu` `chaindata` location.

```
/var/lib/besu/
```


# Maintenance

Notes on how to maintain and update a Besu Client.

### Besu - Update Client

```bash
besu-update
```

### Besu - Update besu.service

```bash
besu-stop
besu-config

# MAKE ANY CHANGES TO THE CONFIG

daemon-reload
besu-start
besu-status
```


# Beacon Clients

{% content-ref url="/pages/wcntNMFmNZRRKeaqDPUE" %}
[Lighthouse](/ethereum-dev/infrastructure/client-software/beacon-clients/lighthouse)
{% endcontent-ref %}

{% content-ref url="/pages/8lTZw6Qj6i4s1xPNWekX" %}
[Teku](/ethereum-dev/infrastructure/client-software/beacon-clients/teku)
{% endcontent-ref %}

## Process - Changing Clients

1. Stop old client.
2. Disable old client.
3. Delete old client data.
4. Enable new client.
5. Start new client.

## UFW Config

Configure the firewall.

{% code title="Beacon Clients" %}

```bash
BEACON_P2P_PORT=              # Default: 9000
BEACON_HTTP_PORT=             # Default: 5052
BEACON_METRICS_PORT=          # Default: 5054

sudo ufw allow ${BEACON_P2P_PORT} comment 'Allow Beacon P2P in'
sudo ufw allow ${BEACON_HTTP_PORT} comment 'Allow Beacon http in'
sudo ufw allow ${BEACON_METRICS_PORT} comment 'Allow Beacon Metrics in'
```

{% endcode %}

## Beacon Service Environment Variables

```bash
sudo vim /etc/default/beacon-variables.env
```

```ini
NETWORK=                            # E.g. mainnet or holesky
BEACON_EXECUTION_ENDPOINTS=         # E.g. http://127.0.0.1:8551
BEACON_P2P_PORT=                    # Default: 9000
BEACON_HTTP_ADDRESS=                # E.g. 0.0.0.0
BEACON_HTTP_PORT=                   # Default: 5052
BEACON_METRICS_ADDR=                # E.g. 0.0.0.0
BEACON_METRICS_PORT=                # E.g. 5054
BEACON_SUGGESTED_FEE_RECIPIENT=     # E.g. 0x0000...
BEACON_CHECKPOINT_SYNC_URL=         # E.g. https://beaconstate.ethstaker.cc
BEACON_BUILDER=                     # E.g. http://127.0.0.1:18550
NGINX_PROXY_BEACON_METRICS_PORT=    # Unified metrics port e.g. 5055
```


# Lighthouse

Notes on how to install, use and maintain Lighthouse BN.

{% content-ref url="/pages/F7eq9WIkaDPLfjXdP6m4" %}
[Installation](/ethereum-dev/infrastructure/client-software/beacon-clients/lighthouse/installation)
{% endcontent-ref %}

{% content-ref url="/pages/pWvCcIeGBYvI6Am8nV4r" %}
[Useful Commands](/ethereum-dev/infrastructure/client-software/beacon-clients/lighthouse/useful-commands)
{% endcontent-ref %}

{% content-ref url="/pages/T84tE00iFx9hBBWSSt9o" %}
[Maintenance](/ethereum-dev/infrastructure/client-software/beacon-clients/lighthouse/maintenance)
{% endcontent-ref %}


# Installation

Lighthouse client installation guide.

## Create Aliases

{% code fullWidth="true" %}

```bash
echo "alias lighthouse-version-current='/usr/local/bin/lighthouse --version'" >> ~/.bashrc
echo "alias lighthouse-build='~/lighthouse-build.sh'" >> ~/.bashrc
echo "alias lighthouse-version-new='~/.cargo/bin/lighthouse --version'" >> ~/.bashrc
echo "alias lighthouse-deploy='~/lighthouse-deploy.sh'" >> ~/.bashrc

echo "alias lighthouse-beacon-log='journalctl -f -u lighthousebeacon.service -o cat | ccze -A'" >> ~/.bashrc
echo "alias lighthouse-beacon-start='sudo systemctl start lighthousebeacon.service'" >> ~/.bashrc
echo "alias lighthouse-beacon-stop='sudo systemctl stop lighthousebeacon.service'" >> ~/.bashrc
echo "alias lighthouse-beacon-restart='sudo systemctl restart lighthousebeacon.service'" >> ~/.bashrc
echo "alias lighthouse-beacon-status='sudo systemctl status lighthousebeacon.service'" >> ~/.bashrc
echo "alias lighthouse-beacon-config='sudo vim /etc/systemd/system/lighthousebeacon.service'" >> ~/.bashrc
echo "alias lighthouse-beacon-enable='sudo systemctl enable lighthousebeacon.service'" >> ~/.bashrc
echo "alias lighthouse-beacon-disable='sudo systemctl disable lighthousebeacon.service'" >> ~/.bashrc
echo "alias lighthouse-beacon-delete-data='sudo rm -rf /var/lib/lighthouse/beacon; sudo mkdir -p /var/lib/lighthouse/beacon; sudo chown -R lighthousebeacon:lighthousebeacon /var/lib/lighthouse/beacon'" >> ~/.bashrc

source ~/.bashrc
```

{% endcode %}

## Dependency - Install Rust

```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

<1>
<ENTER>

source $HOME/.cargo/env
```

Make sure `protoc` is installed otherwise the build will fail.

```bash
sudo apt-get install -y protobuf-compiler
protoc --version
```

## Lighthouse - Install

Build the latest version of `Lighthouse`.

```bash
LIGHTHOUSE_VERSION_COMMIT_HASH=        # e.g.441fc16 

cd ~
git clone https://github.com/sigp/lighthouse.git
cd ~/lighthouse
git checkout ${LIGHTHOUSE_VERSION_COMMIT_HASH}
make
```

Move the compiled `Lighthouse` build to a new directory.

```bash
sudo cp ~/.cargo/bin/lighthouse /usr/local/bin
```

Check version.

```bash
/usr/local/bin/lighthouse --version
```

Create `Lighthouse` directory.

```bash
sudo mkdir -p /var/lib/lighthouse
```

## Firewall Configuration

Configure the firewall using generic Beacon client UFW settings: [Beacon Clients](/ethereum-dev/infrastructure/client-software/beacon-clients#ufw-config)

## Lighthouse BN - Configure Service

Create `lighthousebeacon` user and set permissions.

```bash
sudo useradd --no-create-home --shell /bin/false lighthousebeacon
sudo mkdir -p /var/lib/lighthouse/beacon
sudo chown -R lighthousebeacon:lighthousebeacon /var/lib/lighthouse/beacon
```

Configure [Beacon Clients](/ethereum-dev/infrastructure/client-software/beacon-clients#beacon-service-environment-variables).

Configure `lighthousebeacon` service using the command line flags.

```bash
sudo vim /etc/systemd/system/lighthousebeacon.service
```

{% tabs %}
{% tab title="lighthousebeacon.service" %}
{% code title="lighthousebeacon.service" %}

```bash
[Unit]
Description=Lighthouse Ethereum Client - Beacon Node
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=lighthousebeacon
Group=lighthousebeacon
Restart=always
RestartSec=5

EnvironmentFile=/etc/default/beacon-variables.env

ExecStart=/usr/local/bin/lighthouse bn \
    --network ${NETWORK} \
    --datadir /var/lib/lighthouse \
    --jwt-secrets="/var/lib/jwtsecret" \
    --execution-endpoints ${BEACON_EXECUTION_ENDPOINTS} \
    --port ${BEACON_P2P_PORT} \
    \
    --http \
    --http-address=${BEACON_HTTP_ADDRESS} \
    --http-port=${BEACON_HTTP_PORT} \
    --http-allow-origin "*" \
    \
    --metrics \
    --metrics-address ${BEACON_METRICS_ADDR} \
    --metrics-port ${BEACON_METRICS_PORT} \
    --metrics-allow-origin "*" \
    --validator-monitor-auto \
    \
    --suggested-fee-recipient ${BEACON_SUGGESTED_FEE_RECIPIENT} \
    --checkpoint-sync-url ${BEACON_CHECKPOINT_SYNC_URL} \
    --builder ${BEACON_BUILDER}

[Install]
WantedBy=multi-user.target
```

{% endcode %}
{% endtab %}

{% tab title="Lighthouse BN Flags Explained" %}

| `/usr/local/bin/lighthouse bn`                                                 | Starts the `Beacon` node.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| ------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--network`                                                                    | Name of the chain Lighthouse will sync and follow (e.g. `mainnet` or `goerli`).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `--datadir`                                                                    | Used to specify a custom root data directory for lighthouse keys and databases.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `--port`                                                                       | The TCP/UDP port to listen on for peer discovery.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `--http`                                                                       | <p>Enable the RESTful HTTP API server.</p><ul><li>Disabled by default.</li></ul>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `--http-address`                                                               | Specify the listening address of the server.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `--http-port`                                                                  | Specify the listening port of the server.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `--metrics`                                                                    | <p>Enable the Prometheus metrics HTTP server.</p><ul><li>Disabled by default.</li></ul>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `--validator-monitor-auto`                                                     | <p>When the <code>--validator-monitor-auto</code> flag is supplied, any validator which uses the <code>beacon\_committee\_subscriptions</code> API endpoint will be enrolled for additional monitoring.</p><ul><li>All active validators will use this endpoint each epoch, so you can expect it to detect all local and active validators within several minutes after start up.</li><li><a href="https://lighthouse-book.sigmaprime.io/validator-monitoring.html#automatic"><https://lighthouse-book.sigmaprime.io/validator-monitoring.html#automatic></a></li></ul>                      |
| <p><code>--monitoring-endpoint</code><br><code>(Not curreclty used)</code></p> | <p>Enables the monitoring service for sending system metrics to a remote endpoint.</p><ul><li>This can be used to monitor your setup on certain services (e.g. <a href="https://beaconcha.in/user/settings#app"><https://beaconcha.in/user/settings#app></a>).</li><li>This flag sets the endpoint where the beacon node metrics will be sent.</li><li>Note: This will send information to a remote server which may identify and associate your validators, IP address, and other personal information.</li><li>Always use a HTTPS connection and never provide an untrusted URL.</li></ul> |
| `--execution-endpoints`                                                        | <p>One or more comma-delimited server endpoints for HTTP JSON-RPC connection.</p><ul><li>If multiple endpoints are given the endpoints are used as fallback in the given order.</li></ul>                                                                                                                                                                                                                                                                                                                                                                                                    |
| `--jwt-secrets`                                                                | <p>The JWT secret is automatically generated when <code>Geth</code> is first run and added to <code>/var/lib/goethereum/</code></p><ul><li>This is same location that is pointed to in both the <code>Geth</code> and <code>Lighthouse</code> configuration so that they use the same JWT secret and can talk to each other.</li></ul>                                                                                                                                                                                                                                                       |
| `--suggested-fee-recipient`                                                    | <p>This address receives transaction fees collected from any blocks produced by this node.</p><ul><li>The <code>--suggested-fee-recipient</code> can be provided to the <code>Beacon Node</code> to act as a default value when the validator client does not transmit a <code>suggested\_fee\_recipient</code> to the <code>Beacon Node</code></li></ul>                                                                                                                                                                                                                                    |
| `--checkpoint-sync-url`                                                        | <p>Used to fast sync the chain rather than starting at genesis.</p><ul><li><a href="https://lighthouse-book.sigmaprime.io/checkpoint-sync.html#automatic-checkpoint-sync"><https://lighthouse-book.sigmaprime.io/checkpoint-sync.html#automatic-checkpoint-sync></a></li><li>Only needed for the initial sync, I can remove it after.</li></ul>                                                                                                                                                                                                                                              |
| `--builder`                                                                    | <p>Used to query the provided URL during block production for a block payload with stubbed-out transactions.</p><ul><li>If this request fails, Lighthouse will fall back to the local execution engine and produce a block using transactions gathered and verified locally.</li></ul>                                                                                                                                                                                                                                                                                                       |
| `--reconstruct-historic-states`                                                | <p>Used to reconstruct the history of the beacon chain when checkpoint sync was used.</p><ul><li>Allows access to all historical data.</li><li><a href="https://lighthouse-book.sigmaprime.io/checkpoint-sync.html#reconstructing-states"><https://lighthouse-book.sigmaprime.io/checkpoint-sync.html#reconstructing-states></a></li></ul>                                                                                                                                                                                                                                                   |
| `--purge-db`                                                                   | Add this flag to delete the existing database.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| {% endtab %}                                                                   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| {% endtabs %}                                                                  |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |

Start the service and check it's working as expected.

## Command Aliases

```bash
daemon-reload     # Reload any changes made to the lighthousebeacon.service
lighthouse-beacon-enable     # Enable the lighthousebeacon.service
lighthouse-beacon-start      # Start the lighthousebeacon.service
lighthouse-beacon-status     # View the status of the lighthousebeacon.service

lighthouse-beacon-log        # View the lighthousebeacon.service logs
```

## Lighthouse - Update Scripts

Create `Lighthouse` build script.

```bash
vim ~/lighthouse-build.sh
```

{% code title="\~/lighthouse-build.sh" %}

```bash
#!/bin/bash
set -e
cd ~/lighthouse

read -p "Enter the commit hash you want to checkout: " commit_hash

git fetch
git checkout $commit_hash

echo
echo "********************"
echo "Making Lighthouse..."
echo "********************"
make
```

{% endcode %}

Create `Lighthouse` deploy script.

```bash
vim ~/lighthouse-deploy.sh
```

{% code title="\~/lighthouse-deploy.sh" %}

```bash
#!/bin/bash
# set -e     # This isn't working correctly, so comment out for now

while true; do
    read -p "Are you sure you want to deploy Lighthouse? (Y/N) " yn
    case $yn in
        [Yy]* ) break;;
        [Nn]* ) exit;;
        * ) echo "Please answer Y or N.";;
    esac
done

# Check if the services exist before checking their status
if systemctl list-units --full -all | grep -Fq lighthousebeacon.service; then
    beacon_status=$(sudo systemctl is-active lighthousebeacon.service)
else
    beacon_status="not_installed"
fi

if systemctl list-units --full -all | grep -Fq lighthousevalidator.service; then
    validator_status=$(sudo systemctl is-active lighthousevalidator.service)
else
    validator_status="not_installed"
fi

echo "**********************"

if [ "$beacon_status" = "active" ]; then
    echo "Stopping Lighthouse Beacon..."
    sudo systemctl stop lighthousebeacon.service
elif [ "$beacon_status" = "not_installed" ]; then
    echo "Warning: Lighthouse Beacon service is not installed."
fi

if [ "$validator_status" = "active" ]; then
    echo "Stopping Lighthouse Validator..."
    sudo systemctl stop lighthousevalidator.service
elif [ "$validator_status" = "not_installed" ]; then
    echo "Warning: Lighthouse Validator service is not installed."
fi

echo "Replacing previous version..."

# Check if the file exists before trying to remove it
if [ -f /usr/local/bin/lighthouse ]; then
    sudo rm /usr/local/bin/lighthouse
fi

# Check if the source file exists before copying
if [ -f ~/.cargo/bin/lighthouse ]; then
    sudo cp ~/.cargo/bin/lighthouse /usr/local/bin
else
    echo "Error: Source file does not exist. Installation aborted."
    exit 1
fi

if [ "$beacon_status" = "active" ]; then
    echo "Restarting Lighthouse Beacon..."
    sudo systemctl start lighthousebeacon.service
fi

if [ "$validator_status" = "active" ]; then
    echo "Restarting Lighthouse Validator..."
    sudo systemctl start lighthousevalidator.service
fi
```

{% endcode %}

Make all scripts executable.

```bash
chmod u+x ~/lighthouse-build.sh
chmod u+x ~/lighthouse-deploy.sh
```


# Useful Commands

Notes on how to use a Lighthouse Beacon Node.

### lighthousebeacon.service

{% code fullWidth="true" %}

```bash
lighthouse-beacon-log            # View the lighthousebeacon.service logs
lighthouse-beacon-start          # Start the lighthousebeacon.service
lighthouse-beacon-stop           # Stop the lighthousebeacon.service
lighthouse-beacon-restart        # Restart the lighthousebeacon.service
lighthouse-beacon-status         # View the status of the lighthousebeacon.service
lighthouse-beacon-enable         # Enable the lighthousebeacon.service
lighthouse-beacon-disable        # Disable the lighthousebeacon.service
lighthouse-beacon-delete-data    # Delete all Lighthouse chain data

lighthouse-beacon-config         # Open the /etc/systemd/system/lighthousebeacon.service in vim
daemon-reload                    # Reload any changes made to the lighthousebeacon.service
```

{% endcode %}


# Maintenance

Notes on how to maintain and update a Lighthouse client.

## Lighthouse - Update Client

```bash
lighthouse-version-current    # Check current version number
lighthouse-build              # Download and build latest version
lighthouse-version-new        # Check the version of the newly built client
lighthouse-deploy             # Deploy the new client
```

## Lighthouse - Update lighthousebeacon.service

```bash
lighthouse-beacon-stop
lighthouse-beacon-config

# MAKE ANY CHANGES TO THE CONFIG

daemon-reload
lighthouse-beacon-start
lighthouse-beacon-status
```


# Teku

Notes on how to install, use and maintain Teku BN.

{% content-ref url="/pages/lwMfBUWjIPGPTAZWWXUi" %}
[Installation](/ethereum-dev/infrastructure/client-software/beacon-clients/teku/installation)
{% endcontent-ref %}

{% content-ref url="/pages/2HHmuKr144bGmWaS2ugv" %}
[Useful Commands](/ethereum-dev/infrastructure/client-software/beacon-clients/teku/useful-commands)
{% endcontent-ref %}

{% content-ref url="/pages/TzcSgVhDc3eunQdWGr0a" %}
[Maintenance](/ethereum-dev/infrastructure/client-software/beacon-clients/teku/maintenance)
{% endcontent-ref %}


# Installation

Teku client installation guide.

## Create Aliases

{% code fullWidth="true" %}

```bash
echo "alias teku-version-current='/usr/local/bin/teku/bin/teku --version'" >> ~/.bashrc
echo "alias teku-build='~/teku-build.sh'" >> ~/.bashrc
echo "alias teku-version-new='~/teku/build/install/teku/bin/teku --version'" >> ~/.bashrc
echo "alias teku-deploy='~/teku-deploy.sh'" >> ~/.bashrc

echo "alias teku-beacon-log='journalctl -f -u tekubeacon.service -o cat | ccze -A'" >> ~/.bashrc
echo "alias teku-beacon-start='sudo systemctl start tekubeacon.service'" >> ~/.bashrc
echo "alias teku-beacon-stop='sudo systemctl stop tekubeacon.service'" >> ~/.bashrc
echo "alias teku-beacon-restart='sudo systemctl restart tekubeacon.service'" >> ~/.bashrc
echo "alias teku-beacon-status='sudo systemctl status tekubeacon.service'" >> ~/.bashrc
echo "alias teku-beacon-config='sudo vim /etc/systemd/system/tekubeacon.service'" >> ~/.bashrc
echo "alias teku-beacon-enable='sudo systemctl enable tekubeacon.service'" >> ~/.bashrc
echo "alias teku-beacon-disable='sudo systemctl disable tekubeacon.service'" >> ~/.bashrc
echo "alias teku-beacon-delete-data='sudo rm -rf /var/lib/teku/beacon; sudo mkdir -p /var/lib/teku/beacon; sudo chown -R tekubeacon:tekubeacon /var/lib/teku/beacon'" >> ~/.bashrc

source ~/.bashrc
```

{% endcode %}

## Dependency - Install Java

`Teku` requires version 21+ of Java.

```bash
sudo apt-get install openjdk-21-jre-headless openjdk-21-jdk -y

sudo apt-get install libsodium23 libnss3 -y
```

## Teku - Install

Build the latest version of `Teku`.

```bash
TEKU_VERSION_COMMIT_HASH=        # e.g.508459f 

cd ~
git clone https://github.com/Consensys/teku.git
cd teku
git checkout ${TEKU_VERSION_COMMIT_HASH}
./gradlew installDist
```

Move the compiled `Teku` build to a new directory.

```bash
sudo cp -R ~/teku/build/install/teku /usr/local/bin
```

Check version.

```bash
teku-version-current
```

Create `Teku` directory.

```bash
sudo mkdir -p /var/lib/teku
```

## Firewall Configuration

Configure the firewall using generic Beacon client UFW settings: [Beacon Clients](/ethereum-dev/infrastructure/client-software/beacon-clients#ufw-config)

## Teku BN - Configure Service

Create `tekubeacon` user and set permissions.

```bash
sudo useradd --no-create-home --shell /bin/false tekubeacon
sudo mkdir -p /var/lib/teku/
sudo chown -R tekubeacon:tekubeacon /var/lib/teku/
```

Configure [Beacon Clients](/ethereum-dev/infrastructure/client-software/beacon-clients#beacon-service-environment-variables).

Configure `tekubeacon` service using the command line flags.

```bash
sudo vim /etc/systemd/system/tekubeacon.service
```

{% code title="tekubeacon.service" %}

```bash
[Unit]
Description=Teku Ethereum Client - Beacon Node
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=tekubeacon
Group=tekubeacon
Restart=always
RestartSec=5

EnvironmentFile=/etc/default/beacon-variables.env

ExecStart=/usr/local/bin/teku/bin/teku \
    --network ${NETWORK} \
    --data-path /var/lib/teku/ \
    --ee-jwt-secret-file="/var/lib/jwtsecret" \
    --ee-endpoint ${BEACON_EXECUTION_ENDPOINTS} \
    --p2p-port ${BEACON_P2P_PORT} \
    \
    --rest-api-enabled=true \
    --rest-api-interface=${BEACON_HTTP_ADDRESS} \
    --rest-api-port=${BEACON_HTTP_PORT} \
    --rest-api-host-allowlist "*" \
    \
    --metrics-enabled=true \
    --metrics-interface ${BEACON_METRICS_ADDR} \
    --metrics-port ${BEACON_METRICS_PORT} \
    --metrics-host-allowlist "*" \
    \
    --validators-proposer-default-fee-recipient ${BEACON_SUGGESTED_FEE_RECIPIENT} \
    --initial-state ${BEACON_CHECKPOINT_SYNC_URL} \
    --builder-endpoint ${BEACON_BUILDER} \
    --validators-builder-registration-default-enabled=true \
    # Needed for an SSV block proposal bug
    --validators-graffiti-client-append-format=DISABLED

[Install]
WantedBy=multi-user.target
```

{% endcode %}

Start the service and check it's working as expected.

## Command Aliases

```bash
daemon-reload          # Reload any changes made to the tekubeacon.service
teku-beacon-enable     # Enable the tekubeacon.service
teku-beacon-start      # Start the tekubeacon.service
teku-beacon-status     # View the status of the tekubeacon.service

teku-beacon-log        # View the tekubeacon.service logs
```

## Teku - Update Scripts

Create `Teku` build script.

```bash
vim ~/teku-build.sh
```

{% code title="\~/teku-build.sh" %}

```bash
#!/bin/bash
set -e
cd ~/teku

read -p "Enter the commit hash you want to checkout: " commit_hash

git fetch
git checkout $commit_hash

echo
echo "****************"
echo "Building Teku..."
echo "****************"
./gradlew installDist
```

{% endcode %}

Create `Teku` deploy script.

```bash
vim ~/teku-deploy.sh
```

{% code title="\~/teku-deploy.sh" %}

```bash
#!/bin/bash
# set -e     # This isn't working correctly, so comment out for now

while true; do
    read -p "Are you sure you want to deploy Teku? (Y/N) " yn
    case $yn in
        [Yy]* ) break;;
        [Nn]* ) exit;;
        * ) echo "Please answer Y or N.";;
    esac
done

# Check if the services exist before checking their status
if systemctl list-units --full -all | grep -Fq tekubeacon.service; then
    beacon_status=$(sudo systemctl is-active tekubeacon.service)
else
    beacon_status="not_installed"
fi

if systemctl list-units --full -all | grep -Fq tekuvalidator.service; then
    validator_status=$(sudo systemctl is-active tekuvalidator.service)
else
    validator_status="not_installed"
fi

echo "**********************"

if [ "$beacon_status" = "active" ]; then
    echo "Stopping Teku Beacon..."
    sudo systemctl stop tekubeacon.service
elif [ "$beacon_status" = "not_installed" ]; then
    echo "Warning: Teku Beacon service is not installed."
fi

if [ "$validator_status" = "active" ]; then
    echo "Stopping Teku Validator..."
    sudo systemctl stop tekuvalidator.service
elif [ "$validator_status" = "not_installed" ]; then
    echo "Warning: Teku Validator service is not installed."
fi

echo "Replacing previous version..."

# Check if the directory exists before trying to remove it
if [ -d /usr/local/bin/teku ]; then
    sudo rm -rf /usr/local/bin/teku
fi

# Check if the source directory exists before copying
if [ -d ~/teku/build/install/teku ]; then
    sudo cp -R ~/teku/build/install/teku /usr/local/bin
else
    echo "Error: Source directory does not exist. Installation aborted."
    exit 1
fi

if [ "$beacon_status" = "active" ]; then
    echo "Restarting Teku Beacon..."
    sudo systemctl start tekubeacon.service
fi

if [ "$validator_status" = "active" ]; then
    echo "Restarting Teku Validator..."
    sudo systemctl start tekuvalidator.service
fi
```

{% endcode %}

Make all scripts executable.

```bash
chmod u+x ~/teku-build.sh
chmod u+x ~/teku-deploy.sh
```


# Useful Commands

Notes on how to use a Teku BN.

### tekubeacon.service

{% code fullWidth="false" %}

```bash
teku-beacon-log            # View the tekubeacon.service logs
teku-beacon-start          # Start the tekubeacon.service
teku-beacon-stop           # Stop the tekubeacon.service
teku-beacon-restart        # Restart the tekubeacon.service
teku-beacon-status         # View the status of the tekubeacon.service
teku-beacon-enable         # Enable the tekubeacon.service
teku-beacon-disable        # Disable the tekubeacon.service
teku-beacon-delete-data    # Delete all Teku chain data

teku-beacon-config         # Open the /etc/systemd/system/tekubeacon.service in vim
daemon-reload              # Reload any changes made to the tekubeacon.service
```

{% endcode %}


# Maintenance

Notes on how to maintain and update a Teku client.

## Teku - Update Client

```bash
teku-version-current    # Check current version number
teku-build              # Download and build latest version
teku-version-new        # Check the version of the newly built client
teku-deploy             # Deploy the new client
```

## Teku - Update tekubeacon.service

```bash
teku-beacon-stop
teku-beacon-config

# MAKE ANY CHANGES TO THE CONFIG

daemon-reload
teku-beacon-start
teku-beacon-status
```


# Validator Clients


# Lighthouse

Notes on how to install and maintain a Lighthouse Validator client.

{% content-ref url="/pages/FyoLO2oki0NLJJl4prfP" %}
[Installation](/ethereum-dev/infrastructure/client-software/validator-clients/lighthouse/installation)
{% endcontent-ref %}

{% content-ref url="/pages/tyUc2Jjy7PwM8V5kwJfr" %}
[Useful Commands](/ethereum-dev/infrastructure/client-software/validator-clients/lighthouse/useful-commands)
{% endcontent-ref %}

{% content-ref url="/pages/WctmRdfKKE6KdEM4mcv6" %}
[Maintenance](/ethereum-dev/infrastructure/client-software/validator-clients/lighthouse/maintenance)
{% endcontent-ref %}


# Installation

Lighthouse Validator client installation guide.

* [Create Aliases](#create-aliases)
* [Lighthouse VC - Configure Service](#lighthouse-vc-configure-service)

### Create Aliases

{% code fullWidth="true" %}

```bash
echo "alias lighthouse-validator-log='journalctl -f -u lighthousevalidator.service -o cat | ccze -A'" >> ~/.bashrc
echo "alias lighthouse-validator-start='sudo systemctl start lighthousevalidator.service'" >> ~/.bashrc
echo "alias lighthouse-validator-stop='sudo systemctl stop lighthousevalidator.service'" >> ~/.bashrc
echo "alias lighthouse-validator-restart='sudo systemctl restart lighthousevalidator.service'" >> ~/.bashrc
echo "alias lighthouse-validator-status='sudo systemctl status lighthousevalidator.service'" >> ~/.bashrc
echo "alias lighthouse-validator-config='sudo vim /etc/systemd/system/lighthousevalidator.service'" >> ~/.bashrc
echo "alias lighthouse-validator-enable='sudo systemctl enable lighthousevalidator.service'" >> ~/.bashrc
echo "alias lighthouse-validator-disable='sudo systemctl disable lighthousevalidator.service'" >> ~/.bashrc

source ~/.bashrc
```

{% endcode %}

## Lighthouse VC - Configure Service

Create `lighthousevalidator` user and set permissions.

```bash
sudo useradd --no-create-home --shell /bin/false lighthousevalidator
sudo mkdir -p /var/lib/lighthouse/validators
sudo chown -R lighthousevalidator:lighthousevalidator /var/lib/lighthouse/validators

# <THIS IS NEEDED SO THE VALIDATOR CAN IMPORT THE KEYSTORES>
sudo chmod 700 /var/lib/lighthouse/validators
```

Configure `lighthousevalidator` service using the command line flags.

```bash
sudo vim /etc/systemd/system/lighthousevalidator.service
```

{% tabs %}
{% tab title="/etc/systemd/system/lighthousevalidator.service" %}
{% code title="/etc/systemd/system/lighthousevalidator.service" %}

```bash
[Unit]
Description=Lighthouse Ethereum Client - Validator Client
After=network-online.target
Wants=network-online.target

[Service]
User=lighthousevalidator
Group=lighthousevalidator
Type=simple
Restart=always
RestartSec=5

Environment=NETWORK=                    # E.g. mainnet or holesky
Environment=DATADIR=                    # Default: /var/lib/lighthouse
Environment=GRAFFITI=                   # E.g. For the merge!
Environment=METRICS_PORT=               # Default: 5064
Environment=MONITORING_ENDPOINTS=
Environment=SUGGESTED_FEE_RECIPIENT=
Environment=BEACON_NODES=

ExecStart=/usr/local/bin/lighthouse vc \
    --network ${NETWORK} \
    --datadir ${DATADIR} \
    --graffiti ${GRAFFITI} \
    --metrics \
    --metrics-port ${METRICS_PORT} \
    --monitoring-endpoint ${MONITORING_ENDPOINTS} \
    --enable-doppelganger-protection \
    --suggested-fee-recipient ${SUGGESTED_FEE_RECIPIENT} \
    --builder-proposals \
    --beacon-nodes ${BEACON_NODES}

[Install]
WantedBy=multi-user.target
```

{% endcode %}
{% endtab %}

{% tab title="Lighthouse VC Flags Explained" %}

| `/usr/local/bin/lighthouse vc`     | Starts the validator node                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--network`                        | <p>Name of the chain Lighthouse will sync and follow</p><ul><li>Possible values:</li><li><p></p><ul><li>mainnet</li><li>prater</li><li>gnosis</li><li>kiln</li><li>ropsten</li></ul></li></ul>                                                                                                                                                                                                                                                                                                                                                                                                           |
| `--datadir`                        | Used to specify a custom root data directory for lighthouse keys and databases                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `--graffiti`                       | Specify your custom graffiti to be included in blocks                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `--monitoring-endpoint`            | Set to a monitoring service e.g. [https://beaconcha.in](https://beaconcha.in/)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `--enable-doppelganger-protection` | <p>Protects from the chance of two instances of the validator starting on the same system</p><p><a href="https://lighthouse-book.sigmaprime.io/validator-doppelganger.html"><https://lighthouse-book.sigmaprime.io/validator-doppelganger.html></a></p><p><br>Not perfect, and does have a penalty of waiting for 2-3 epochs (approx. 6.4 minutes per epoch)</p><p><br>It's a bit annoying to miss a few attestations, and would be very sad to miss a block, but the chance of me being a block proposer during that downtime is very low, and the benefits of not getting slashed are much greater</p> |
| `--metrics`                        | <p>Enable the Prometheus metrics HTTP server</p><ul><li>Disabled by default</li></ul>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `--suggested-fee-recipient`        | The fallback address provided to the `Beacon Node` if nothing suitable is found in the validator definitions or fee recipient file                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| {% endtab %}                       |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| {% endtabs %}                      |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |

Start the service and check it's working as expected.

## Command Aliases

```bash
daemon-reload        # Reload any changes made to the lighthousevalidator.service
lighthouse-validator-enable     # Enable the lighthousevalidator.service
lighthouse-validator-start      # Start the lighthousevalidator.service
lighthouse-validator-status     # View the status of the lighthousevalidator.service

lighthouse-validator-log        # View the lighthousevalidator.service logs
```

At this point, the `lighthousevalidator.service` is running with no keystores.

So it will just show a message saying something like `No validators present` which is fine.


# Useful Commands

Notes on how to use a Lighthouse Validator Client.

### lighthousevalidator.service

```bash
lighthouse-validator-log        # View the lighthousevalidator.service logs
lighthouse-validator-start      # Start the lighthousevalidator.service
lighthouse-validator-stop       # Stop the lighthousevalidator.service
lighthouse-validator-restart    # Restart the lighthousevalidator.service
lighthouse-validator-status     # View the status of the lighthousevalidator.service
lighthouse-validator-enable     # Enable the lighthousevalidator.service
lighthouse-validator-disable    # Disable the lighthousevalidator.service

lighthouse-validator-config     # Open the /etc/systemd/system/lighthousevalidator.service in vim
daemon-reload                   # Reload any changes made to the lighthousevalidator.service
```


# Maintenance

Notes on how to maintain and update a Lighthouse Validator Client.

### Lighthouse - Update lighthousevalidator.service

```bash
lighthouse-validator-stop
lighthouse-validator-config

# MAKE ANY CHANGES TO THE CONFIG

daemon-reload
lighthouse-validator-start
lighthouse-validator-status
```


# MEV Boost

Notes on how to install and maintain an MEV Boost client.

{% content-ref url="/pages/q74OziHj3Dj0p3rkTjle" %}
[Installation](/ethereum-dev/infrastructure/client-software/mev-boost/installation)
{% endcontent-ref %}

{% content-ref url="/pages/HoLtWx5RwSgemzdtkB6A" %}
[Maintenance](/ethereum-dev/infrastructure/client-software/mev-boost/maintenance)
{% endcontent-ref %}


# Installation

MEV Boost client installation guide.

* [Create Aliases](#create-aliases)
* [Firewall Configuration](#firewall-configuration)
* [MEV Boost - Install](#mev-boost-install)
* [MEV Boost - Configure Service](#mev-boost-configure-service)
* [MEV Boost - Update Scripts](#mev-boost-update-scripts)

### Create Aliases

```bash
echo "alias mev-log='journalctl -f -u mevboost.service -o cat | ccze -A'" >> ~/.bashrc
echo "alias mev-start='sudo systemctl start mevboost.service'" >> ~/.bashrc
echo "alias mev-stop='sudo systemctl stop mevboost.service'" >> ~/.bashrc
echo "alias mev-restart='sudo systemctl restart mevboost.service'" >> ~/.bashrc
echo "alias mev-status='sudo systemctl status mevboost.service'" >> ~/.bashrc
echo "alias mev-config='sudo vim /etc/systemd/system/mevboost.service'" >> ~/.bashrc
echo "alias mev-enable='sudo systemctl enable mevboost.service'" >> ~/.bashrc
echo "alias mev-disable='sudo systemctl disable mevboost.service'" >> ~/.bashrc
echo "alias mev-update='~/mev-update.sh'" >> ~/.bashrc

source ~/.bashrc
```

### MEV Boost - Install

Build the latest version of `MEV Boost`.

```bash
MEV_VERSION_COMMIT_HASH=        # e.g.441fc16

cd ~
git clone https://github.com/flashbots/mev-boost.git
cd ~/mev-boost
git checkout ${MEV_VERSION_COMMIT_HASH}
make build
```

Move the compiled `MEV Boost` build to a new directory.

```bash
sudo cp ~/mev-boost/mev-boost /usr/local/bin
```

Create `MEV Boost` user and directory.

```bash
sudo useradd --no-create-home --shell /bin/false mevboost
sudo chown -R mevboost:mevboost ~/mev-boost
```

### MEV Boost - Configure Service

Configure `MEV Boost` service using the command line flags.

```bash
sudo vim /etc/systemd/system/mevboost.service
```

{% tabs %}
{% tab title="/etc/systemd/system/mevboost.service" %}
{% code title="/etc/systemd/system/mevboost.service" %}

```bash
[Unit]
Description=mev-boost
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
User=mevboost
Group=mevboost
Restart=always
RestartSec=5

Environment=NETWORK=        # E.g. mainnet or holesky
Environment=ADDR_IP=        # E.g. 0.0.0.0
Environment=ADDR_PORT=      # Default: 18550
Environment=MIN_BID=        # E.g. 0.01
Environment=RELAYS=         # E.g. "https://<HASH>@relay.ultrasound.money"

ExecStart=/usr/local/bin/mev-boost \
    -${NETWORK} \
    -addr ${ADDR_IP}:${ADDR_PORT} \
    -min-bid ${MIN_BID} \
    -relay-check \
    -relays ${RELAYS}

[Install]
WantedBy=multi-user.target
```

{% endcode %}
{% endtab %}

{% tab title="MEV Boost Flags Explained" %}

<table data-header-hidden><thead><tr><th width="294">Flag</th><th>Description</th></tr></thead><tbody><tr><td><code>/usr/local/bin/mev-boost</code></td><td>Starts MEV Boost.</td></tr><tr><td><code>-${NETWORK}</code></td><td>Specifies the target network.</td></tr><tr><td><code>-addr</code></td><td>Set listening port.</td></tr><tr><td><code>-min-bid</code></td><td>Sets the minimum bid that needs to be offered to accept a block from the relay.<br><br>If no offer is higher than the <code>min-bid</code> then the validator will build its own block locally. </td></tr><tr><td><code>-relay-check</code></td><td>MEV Boost pings the relays to check they are still alive.</td></tr><tr><td><code>-relays</code></td><td>Comma separated list of relay addresses.</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

Start the service and check it's working as expected.

{% tabs %}
{% tab title="Command Aliases" %}

```bash
daemon-reload      # Reload any changes made to the mevboost.service
mev-enable         # Enable the mevboost.service
mev-start          # Start the mevboost.service
mev-status         # View the status of the mevboost.service

mev-log            # View the mevboost.service logs
```

{% endtab %}

{% tab title="Full Commands" %}

```bash
sudo systemctl daemon-reload                              # Reload any changes made to the mevboost.service
sudo systemctl enable mevboost.service                    # Enable the mevboost.service
sudo systemctl start mevboost.service                     # Start the mevboost.service
sudo systemctl status mevboost.service                    # View the status of the mevboost.service

sudo journalctl -f -u mevboost.service -o cat | ccze -A   # View the mevboost.service logs
```

{% endtab %}
{% endtabs %}

### MEV Boost - Update Scripts

Create `MEV Boost` update script.

```bash
vim ~/mev-update.sh
```

{% code title="\~/mev-update.sh" %}

```bash
#!/bin/bash
set -e

while true; do
    read -p "Are you sure you want to update MEV Boost? (Y/N) " yn
    case $yn in
        [Yy]* ) break;;
        [Nn]* ) exit;;
        * ) echo "Please answer Y or N.";;
    esac
done

cd ~/
sudo rm -rf mev-boost
git clone https://github.com/flashbots/mev-boost.git
cd mev-boost

read -p "Enter the commit hash you want to checkout: " commit_hash

git fetch
git checkout $commit_hash

echo
echo "*******************"
echo "Making MEV Boost..."
echo "*******************"
make build

# Check if mevboost.service exists and is running
service_was_running=0
if sudo systemctl is-active --quiet mevboost.service; then
    service_was_running=1
    echo "*********************"
    echo "Stopping MEV Boost..."
    sudo systemctl stop mevboost.service
fi

echo "Replacing previous version..."
sudo rm /usr/local/bin/mev-boost
sudo cp ~/mev-boost/mev-boost /usr/local/bin

# Only start mevboost.service if it was running originally
if [ $service_was_running -eq 1 ]; then
    echo "Restarting MEV Boost..."
    echo "***********************"
    sudo systemctl start mevboost.service
fi
```

{% endcode %}

Make the script executable.

```bash
chmod u+x ~/mev-update.sh
```


# Maintenance

Notes on how to maintain and update an MEV Boost client.

### MEV Boost - Update Client

```bash
mev-update
```

### MEV Boost - Update mevboost.service

```bash
mev-stop
mev-config

# MAKE ANY CHANGES TO THE CONFIG

daemon-reload
mev-start
mev-status
```


# Alerting and Monitoring

Each machine runs a Prometheus and Alertmanager instance which monitors the services running on the same machine.

If Prometheus and/or Alertmanager are down, or the entire machine is down/unresponsive then HealthChecks.io is used as a dead-mans-hand alert. Periodic heartbeat pings are sent by a cron script (`~/healthchecks.sh`) every 5 minutes, with a 10 minute grace period.

All services are integrated with PagerDuty for alerts.

{% content-ref url="/pages/ud8BcY3LqFgG7wrR9MNH" %}
[Prometheus](/ethereum-dev/infrastructure/alerting-and-monitoring/prometheus)
{% endcontent-ref %}

{% content-ref url="/pages/fOljlY8Mdp94TYLZMrg2" %}
[HealthChecks.io](/ethereum-dev/infrastructure/alerting-and-monitoring/healthchecks.io)
{% endcontent-ref %}

{% content-ref url="/pages/tuIrcOP19fAC24doLzOB" %}
[PagerDuty](/ethereum-dev/infrastructure/alerting-and-monitoring/pagerduty)
{% endcontent-ref %}


# Prometheus

## UFW Config

```bash
sudo ufw allow 9090 comment 'Allow Prometheus UI in'
sudo ufw allow 9093 comment 'Allow Alertmanager UI in'
```

## Docker Config

### Create Directories

{% code fullWidth="false" %}

```bash
mkdir ~/alerting
mkdir ~/alerting/prometheus
mkdir ~/alerting/alertmanager
```

{% endcode %}

{% hint style="info" %}
Since prometheus doesn't support direct variable replacement in the .yml configuration, I'm using a template and script to run when the docker image starts to create the prometheus.yml file dynamically.

This is useful so it uses the correct ports from the execution and beacon config files automatically.
{% endhint %}

### Prometheus Entrypoint Script

```bash
vim ~/alerting/prometheus/entrypoint.sh
```

```bash
#!/bin/sh

# Source environment variables
source /etc/default/execution-variables.env
source /etc/default/beacon-variables.env
export $(cut -d= -f1 /etc/default/execution-variables.env)
export $(cut -d= -f1 /etc/default/beacon-variables.env)

# Output file
OUTPUT="/tmp/prometheus.yml"

# Start with an empty output file
: > "$OUTPUT"

# Process the template file with awk to replace environment variables
awk '{
    while (match($0, /\$\{[^}]+\}/)) {
        varname = substr($0, RSTART + 2, RLENGTH - 3);
        value = ENVIRON[varname];
        if (value == "") value = "UNDEFINED";
        $0 = substr($0, 1, RSTART - 1) value substr($0, RSTART + RLENGTH);
    }
    print;
}' "/etc/prometheus/prometheus.yml.template" > "$OUTPUT"

# Continue with Prometheus startup
exec /bin/prometheus "$@"
```

```bash
# Make the scrip executable by everyone, not just the current user
chmod +x ~/alerting/prometheus/entrypoint.sh
```

### Create Docker Compose

```bash
vim ~/alerting/docker-compose.yml
```

```yaml
services:
  prometheus:
    image: prom/prometheus:latest
    restart: unless-stopped
    network_mode: host
    volumes:
      - ./prometheus:/etc/prometheus
      - ./prometheus/alert.rules.yml:/etc/prometheus/alert.rules.yml
      - /etc/default/execution-variables.env:/etc/default/execution-variables.env
      - /etc/default/beacon-variables.env:/etc/default/beacon-variables.env
    entrypoint: ["/etc/prometheus/entrypoint.sh"]
    command:
      - '--config.file=/tmp/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.enable-lifecycle'

  alertmanager:
    image: prom/alertmanager:latest
    depends_on:
      - prometheus
    restart: unless-stopped
    network_mode: host
    volumes:
      - ./alertmanager:/etc/alertmanager
    command:
      - '--config.file=/etc/alertmanager/alertmanager.yml'
      - '--storage.path=/alertmanager'
```

## Prometheus Config

{% hint style="info" %}
Since each client has a different URL path for metrics, and I want a unified endpoint for Prometheus to use, configure an NGINX server to redirect requests to a single endpoint.

It will try each possible endpoint until it finds the actively running client, and if it doesn't find any, it will assume that it is down.
{% endhint %}

### Install NGINX

```bash
sudo apt-get update
sudo apt-get install -y nginx
```

### NGINX Config Script

{% hint style="info" %}
Edit this script to add additional client metrics paths.
{% endhint %}

```bash
sudo vim /etc/default/nginx-config-script.sh
```

{% code fullWidth="true" %}

```bash
#!/bin/bash

source /etc/default/execution-variables.env
source /etc/default/beacon-variables.env

EXECUTION_METRICS_FULL_URL=""
BEACON_METRICS_FULL_URL=""

# ******************
# EXECUTION CLIENTS
# ******************
# Check if Geth service is running
status_code=$(curl -o /dev/null -s -w "%{http_code}" http://localhost:${EXECUTION_METRICS_PORT}/debug/metrics/prometheus)
if [ "$status_code" = "200" ]; then
  EXECUTION_METRICS_FULL_URL=http://localhost:${EXECUTION_METRICS_PORT}/debug/metrics/prometheus
fi

# Check if Besu service is running
status_code=$(curl -o /dev/null -s -w "%{http_code}" http://localhost:${EXECUTION_METRICS_PORT}/metrics)
if [ "$status_code" = "200" ]; then
  EXECUTION_METRICS_FULL_URL=http://localhost:${EXECUTION_METRICS_PORT}/metrics
fi

# ***************
# BEACON CLIENTS
# ***************
# Check if LH or Teku service is running (they both use /metrics)
status_code=$(curl -o /dev/null -s -w "%{http_code}" http://localhost:${BEACON_METRICS_PORT}/metrics)
if [ "$status_code" = "200" ]; then
  BEACON_METRICS_FULL_URL=http://localhost:${BEACON_METRICS_PORT}/metrics
fi

export $(cut -d= -f1 /etc/default/execution-variables.env)
export $(cut -d= -f1 /etc/default/beacon-variables.env)
export EXECUTION_METRICS_FULL_URL
export BEACON_METRICS_FULL_URL

VARS='${NGINX_PROXY_EXECUTION_METRICS_PORT},\
${EXECUTION_METRICS_FULL_URL},\
${NGINX_PROXY_BEACON_METRICS_PORT},\
${BEACON_METRICS_FULL_URL}'
envsubst "$VARS" < /etc/nginx/sites-available/default.template > /etc/nginx/sites-available/default

echo "Configuration for NGINX has been updated."
```

{% endcode %}

```bash
sudo chmod +x /etc/default/nginx-config-script.sh
```

### NGINX Service Config

* Edit the NGINX service file to run the `/etc/default/nginx-config-script.sh` script before every start.

```bash
sudo vim /lib/systemd/system/nginx.service
```

```ini
[Unit]
Description=A high performance web server and a reverse proxy server
Documentation=man:nginx(8)
After=network.target nss-lookup.target

[Service]
Type=forking
PIDFile=/run/nginx.pid

# ***********
# CHANGE HERE
# ↓↓↓↓↓↓↓↓↓↓↓
ExecStartPre=/usr/bin/sudo /etc/default/nginx-config-script.sh

ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;'
ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'
ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload
ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid
TimeoutStopSec=5
KillMode=mixed

[Install]
WantedBy=multi-user.target
```

```bash
daemon-reload
```

### NGINX Service - Restart CRON

* I couldn't get the NGINX service to reliably wait for the EL/BN to start, so as a workaround, run this script with CRON every minute, and if NGINX isn't running, manually restart the service.

```bash
sudo vim /etc/default/nginx-service-restart-cron-script.sh
```

```bash
#!/bin/bash

# Check if NGINX is active (running)
if ! systemctl is-active --quiet nginx; then
    echo "NGINX is not running. Attempting to restart..."
    # Reset the systemd state for NGINX to clear any failure states
    sudo systemctl reset-failed nginx
    # Attempt to restart NGINX
    sudo systemctl restart nginx
    echo "NGINX restart attempted."
fi
```

```bash
sudo chmod u+x /etc/default/nginx-service-restart-cron-script.sh
```

```bash
sudo crontab -e
```

* Runs every minute.

```
* * * * * /etc/default/nginx-service-restart-cron-script.sh
```

### NGINX Template

```bash
sudo vim /etc/nginx/sites-available/default.template
```

```nginx
server {
    listen ${NGINX_PROXY_EXECUTION_METRICS_PORT};
    server_name localhost;

    location / {
        proxy_pass ${EXECUTION_METRICS_FULL_URL};
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_cache_bypass $http_upgrade;
        proxy_hide_header Access-Control-Allow-Origin;
    }
}

server {
    listen ${NGINX_PROXY_BEACON_METRICS_PORT};
    server_name localhost;

    location / {
        proxy_pass ${BEACON_METRICS_FULL_URL};
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_cache_bypass $http_upgrade;
        proxy_hide_header Access-Control-Allow-Origin;
    }
}
```

```bash
sudo nginx -t
sudo systemctl restart nginx
```

### Prometheus.yml Template

```bash
vim ~/alerting/prometheus/prometheus.yml.template
```

```yaml
global:
  scrape_interval: 30s
  evaluation_interval: 30s

rule_files:
  - "/etc/prometheus/alert.rules.yml"

alerting:
  alertmanagers:
  - static_configs:
    - targets:
      - 'localhost:9093'

scrape_configs:
  - job_name: "execution"
    metrics_path: /
    static_configs:
      - targets: ["localhost:${NGINX_PROXY_EXECUTION_METRICS_PORT}"]
  - job_name: "beacon"
    metrics_path: /
    static_configs:
      - targets: ["localhost:${NGINX_PROXY_BEACON_METRICS_PORT}"]
```

## Alerts Config

```bash
vim ~/alerting/prometheus/alert.rules.yml
```

{% code fullWidth="false" %}

```yaml
groups:
- name: ServiceDownAlerts
  rules:
  - alert: ServiceDown
    expr: up == 0
    for: 20m
    labels:
      severity: critical
    annotations:
      summary: "Service {{ $labels.job }} down"
      description: "{{ $labels.job }} has been down for more than 20 minutes."
```

{% endcode %}

## Alertmanager Config

```bash
vim ~/alerting/alertmanager/alertmanager.yml
```

* Edit `PAGERDUTY_SERVICE_API_KEY`

```yaml
receivers:
- name: 'pagerduty'
  pagerduty_configs:
  # ***********
  # CHANGE HERE
  # ↓↓↓↓↓↓↓↓↓↓↓
  - service_key: '<PAGERDUTY_SERVICE_API_KEY>'
    severity: 'critical'
    send_resolved: true

route:
  group_by: ['alertname', 'cluster']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  receiver: 'pagerduty'
  routes:
  - match:
      severity: critical
    receiver: 'pagerduty'
```

{% code title="Start the Docker container" %}

```bash
cd ~/alerting
docker compose up -d

# View logs to check it has started up correctly
docker compose logs -f
```

{% endcode %}


# HealthChecks.io

## Create a new check

{% embed url="<https://healthchecks.io>" %}

* These settings allow for a system restart without triggering the alerts
* Period:
  * 5 minutes
  * The expected time between pings
* Grace Time:
  * 10 minutes
  * When a check is late, how long to wait to send an alert

## Bash script

Used to monitor if Prometheus and Alertmanager are running, and if the entire machine is offline or unresponsive.

```bash
sudo vim /etc/default/healthchecks.sh
```

* Edit `UNIQUE_ID`

```bash
#!/bin/bash

# Healthchecks.io URL
# ***********
# CHANGE HERE
# ↓↓↓↓↓↓↓↓↓↓↓
healthchecks_io_url="https://hc-ping.com/<UNIQUE_ID>"

# URLs for the health endpoints of Prometheus and Alertmanager
prometheus_health_url="http://localhost:9090/-/healthy"
alertmanager_health_url="http://localhost:9093/-/healthy"

# Check health of Prometheus
if curl -f ${prometheus_health_url}; then
  # Check health of Alertmanager
  if curl -f ${alertmanager_health_url}; then
    # Send heartbeat to Healthchecks.io
    curl -fsS --retry 3 ${healthchecks_io_url} > /dev/null
  else
    echo "Alertmanager is not healthy."
  fi
else
  echo "Prometheus is not healthy."
fi
```

```bash
sudo chmod u+x /etc/default/healthchecks.sh
```

## Configure CRON

* Run every 1 minute.

```bash
sudo crontab -e
```

```
* * * * * /etc/default/healthchecks.sh
```

## Integrations

Integrates with [PagerDuty](/ethereum-dev/infrastructure/alerting-and-monitoring/pagerduty) for alerts.


# PagerDuty

{% embed url="<https://pagerduty.com>" %}


# Ethereum Notes


# Technical Basics

## Why 0x?

In Ethereum, and more broadly in the world of cryptography and blockchain technology, the prefix `0x` is used everywhere... but why?

The prefix `0x` indicates that the following string is in hexadecimal (base 16) format. Hexadecimal is a numeral system that uses 16 symbols: 0-9 to represent values 0 to 9 and A-F to represent values 10 to 15.

```
Base 10:     0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Hexadecimal: 0 1 2 3 4 5 6 7 8 9 A  B  C  D  E  F
```

By starting with `0x` Ethereum ensures no ambiguity about the data format.

{% hint style="info" %}
`0x` means "The string that follows is a hexadecimal!"
{% endhint %}

For example, an Ethereum address looks like `0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266` and is represented in a hexadecimal format.

<table><thead><tr><th width="172">Type</th><th>Value</th></tr></thead><tbody><tr><td>Hexadecimal</td><td><code>f39Fd6e51aad88F6F4ce6aB8827279cffFb92266</code></td></tr><tr><td>Base 10</td><td><code>1390849295786071768276380950238675083608645509734</code></td></tr><tr><td>Base 2 (Binary)</td><td><code>1111001110011111110101101110010100011010101011011000100011110110111101001100111001101010101110001000001001110010011110011100111111111111101110010010001001100110</code></td></tr></tbody></table>

You'll notice from the table that the hexadecimal representation is the shortest number of characters.&#x20;

> Each hexadecimal digit represents four binary digits (bits).

This means a long binary string can be represented by a much shorter hexadecimal string, making it easier to read, write, and communicate.

<div data-full-width="true"><figure><img src="/files/bDhG0wf07vbNaVJnVJqM" alt=""><figcaption><p><a href="https://medium.com/portis/part-two-turning-random-numbers-into-an-ethereum-address-3928f56b225c">https://medium.com/portis/part-two-turning-random-numbers-into-an-ethereum-address-3928f56b225c</a></p></figcaption></figure></div>

## uint8 - Smallest Solidity Example

A `uint8` in Solidity is an unsigned integer that can hold values from 0 to 255.&#x20;

It uses 8 bits (1 byte) to represent these values.

An 8-bit binary number can range from `00000000` (0) to `11111111` (255). For example, the number 150 in binary is `10010110`.

Group the 8 bits into two 4-bit groups (nibbles): `1001` and `0110`.

**Convert to Hexadecimal**:

* `1001` in binary is `9` in hexadecimal.
* `0110` in binary is `6` in hexadecimal.

Thus, the binary `10010110` becomes `0x96` in hexadecimal.

In Solidity, these are equivalent statements:

```solidity
uint8 public myNumberDecimal = 150;
uint8 public myNumberHex = 0x96;
```

## uint256 - Biggest Solidity Example

A `uint256` variable can hold values from `0` to `2^256 - 1`.

**Maximum `uint256` value**

* Base 10: `115792089237316195423570985008687907853269984665640564039457584007913129639935`
* Hexadecimal: `0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`

A 256-bit binary number can range from 00000000…00000000 (0) to 11111111…11111111 (2^256 - 1).

* `uint256` means it is an unsigned integer that uses 256 bits.
* 256 bits = 32 bytes (since 1 byte = 8 bits).


# Ethereum Addresses

## Ethereum Addresses

Ethereum addresses are 40 hexadecimal characters long, excluding the "0x" prefix. This makes each address 20 bytes (160 bits) in length.

* **20 Bytes Long**: An Ethereum address is derived from the last 20 bytes of the Keccak-256 hash of the public key.
* **160 Bits**: This length provides a vast address space, which helps avoid address collisions and enhances security.

## How to get a Private Key

When you got your first Ethereum address, you mostly likely used a tool like MetaMask or a Ledger which gave you a `Seed Phrase`. But that `Seed Phrase` is a string of 12-24 words, so how does that relate to your address?

{% code title="Seed Phrase Example" %}

```
twin galaxy such vague current rhythm about laundry upset fatigue fragile whisper
```

{% endcode %}

The specific words chosen matter, and the details of how they work can be found here:

{% embed url="<https://bips.dev/39/>" %}

A single `Seed Phrase` can be used to generate a nearly infinite number of Ethereum addresses. Those addresses are generated using a specific hierarchical deterministic derivation path explained in great detail [here](https://medium.com/myetherwallet/hd-wallets-and-derivation-paths-explained-865a643c7bf2).

{% hint style="info" %}
What if you want to generate your own `Private Key`? Well since a `Private Key` is simply a binary number 256 digits long, you could flip a coin 256 times counting heads as 1 and tails as 0.
{% endhint %}

## Step-by-Step Example

<table data-full-width="false"><thead><tr><th width="179">Type</th><th>Value</th></tr></thead><tbody><tr><td>Seed Phrase</td><td><code>twin galaxy such vague current rhythm about laundry upset fatigue fragile whisper</code></td></tr><tr><td>Private Key<br>Base 2 (Binary)</td><td><code>1010011111101000000011001001111010101100011110010111100010000101110010101101100011010110101111011111101010100110011000111110000100101111100100011101110101100100001110101100000000011111111100111000111001010010111110011100110000110101110010010010010100011011</code></td></tr><tr><td>Private Key<br>Hexadecimal</td><td><code>0xa7e80c9eac797885cad8d6bdfaa663e12f91dd643ac01ff38e52f9cc35c9251b</code></td></tr></tbody></table>

{% embed url="<https://codepen.io/EridianAlpha/pen/NWVvBaQ>" fullWidth="true" %}
Live example showing Ethereum address derivation from a private key
{% endembed %}

<details>

<summary>Code to generate an Ethereum address from a private key</summary>

{% code fullWidth="true" %}

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Ethereum Public Key Generator</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/ethers/6.13.0/ethers.umd.min.js"></script>
    <style>
        .inline-label {
            font-weight: bold;
            display: inline;
        }
        .value {
            margin-top: 0px;
        }
        .highlight {
            color: cornflowerblue;
        }
    </style>
</head>
<body style="background-color: #14171C; color: white;">
    <label class="inline-label" for="privateKey">1. Enter Private Key:</label>
    <input  style="width: 500px;" type="text" id="privateKey" placeholder="0x..." value="0xa7e80c9eac797885cad8d6bdfaa663e12f91dd643ac01ff38e52f9cc35c9251b">
    <button onclick="generatePublicKey()">Generate Public Key</button>
    <br>
    <br>
    <pre class="inline-label">2. Public Key:</pre>
    <pre class="value" id="publicKey">...</pre>
    <pre class="inline-label">3. Keccak-256 Hash of Public Key:</pre>
    <pre class="value" id="publicKeyHash">...</pre>
    <pre class="inline-label">4. Ethereum Address:</pre>
    <pre class="value" id="ethereumAddress">...</pre>

    <script>
        let wallet;
        let publicKey;
        function generatePublicKey() {
            const privateKeyInput = document.getElementById('privateKey').value.trim();

            // Ensure the private key starts with "0x"
            const privateKey = privateKeyInput.startsWith('0x') ? privateKeyInput : '0x' + privateKeyInput;

            // Validate the private key length (64 characters for the hex representation, 66 with "0x")
            if (privateKey.length !== 66) {
                document.getElementById('publicKey').innerText = 'Invalid private key length';
                return;
            }

            try {
                // Create the Ethers wallet object from the privateKey
                wallet = new ethers.Wallet(privateKey);
                publicKey = wallet.signingKey.publicKey;
                document.getElementById('publicKey').innerText = publicKey;
            } catch (error) {
                document.getElementById('publicKey').innerText = 'Invalid publicKey';
                wallet = null;
                publicKey = null;
                console.error(error);
            }

            try {
                // Slice the `0x04` from the start of the publicKey
                const publicKeyFormatted = '0x' + publicKey.slice(4);

                // Convert the public key to a byte array using ethers.getBytes.
                const publicKeyBytes = ethers.getBytes(publicKeyFormatted);
                
                // Perform Keccak-256 hash of the public key
                const publicKeyHash = ethers.keccak256(publicKeyBytes);

                // Highlight the last 40 characters
                const start = publicKeyHash.slice(0, -40);
                const end = publicKeyHash.slice(-40);
                const highlightedHash = `${start}<span class="highlight">${end}</span>`;
                document.getElementById('publicKeyHash').innerHTML = highlightedHash;
            } catch (error) {
                document.getElementById('publicKeyHash').innerText = 'Invalid publicKeyHash';
                console.error(error);
            }

            try {
                const ethereumAddress = wallet.address

                // Highlight the last 40 characters
                const start = ethereumAddress.slice(0, -40);
                const end = ethereumAddress.slice(-40);
                const highlightedEthereumAddress = `${start}<span class="highlight">${end}</span>`;
                document.getElementById('ethereumAddress').innerHTML = highlightedEthereumAddress;
            } catch (error) {
                document.getElementById('ethereumAddress').innerText = 'Invalid ethereumAddress';
                console.error(error);
            }
        }
        window.onload = generatePublicKey;
    </script>
</body>
</html>

```

{% endcode %}

</details>

1. **Generate a Private Key.** This is a random 256-bit number. For simplicity, let's use a hexadecimal representation:&#x20;

{% code title="Private Key" %}

```
0xa7e80c9eac797885cad8d6bdfaa663e12f91dd643ac01ff38e52f9cc35c9251b
```

{% endcode %}

2. **Generate the Public Key.** The public key is derived from the private key using Elliptic Curve Cryptography (ECC), specifically the secp256k1 curve. The resulting public key is a 512-bit number (128 hexadecimal characters):

```javascript
wallet = new ethers.Wallet(privateKey);
publicKey = wallet.signingKey.publicKey;
```

{% code title="Public Key" overflow="wrap" %}

```
0x04f743d6226bab9de56e067f068371bbe1967ab0f8b32c86b0360f5c9a8dfd3fd03994f9babf7b5efcec75c78f9efa4668df930da585b1d57b8c2b4f7de5a6849d
```

{% endcode %}

3. **Keccak-256 Hash of the Public Key.** Ethereum uses the Keccak-256 hash function (a variant of SHA-3) to hash the public key. Note that only the x and y coordinates of the public key (excluding the initial '0x04' byte) are hashed.

```javascript
// Slice the `0x04` from the start of the publicKey
const publicKeyFormatted = '0x' + publicKey.slice(4);

// Convert the public key to a byte array using ethers.getBytes.
const publicKeyBytes = ethers.getBytes(publicKeyFormatted);

// Perform Keccak-256 hash of the public key
const publicKeyHash = ethers.keccak256(publicKeyBytes);
```

{% code title="Public Key (no '0x04')" overflow="wrap" %}

```
0xf743d6226bab9de56e067f068371bbe1967ab0f8b32c86b0360f5c9a8dfd3fd03994f9babf7b5efcec75c78f9efa4668df930da585b1d57b8c2b4f7de5a6849d
```

{% endcode %}

{% code title="Keccak-256 Hash" %}

```
0x624d10d9dd0d1f68800320293872e96f79890737fcf74aa85d6d760a5a451fe9
```

{% endcode %}

{% hint style="info" %}
The initial '0x04' byte is a prefix used in the uncompressed format of an elliptic curve public key. This prefix indicates that the public key is represented in an uncompressed form, which includes both the x and y coordinates of the point on the elliptic curve.

**Uncompressed Format**:

* The public key consists of a prefix '0x04' followed by the x coordinate and the y coordinate of the elliptic curve point.
* The format is: `0x04 <x-coordinate> <y-coordinate>`

**Compressed Format**:

* The public key consists of a prefix '0x02' or '0x03' followed by only the x coordinate.
* The prefix '0x02' is used if the y coordinate is even, and '0x03' is used if the y coordinate is odd.

The '0x04' prefix is removed because it is not part of the essential elliptic curve point data (x and y coordinates). It merely indicates that the data following it is an uncompressed public key. For the purpose of hashing and deriving the Ethereum address, only the actual coordinates of the elliptic curve point are relevant, and thus the prefix is excluded.
{% endhint %}

4. **Ethereum Address.** The Ethereum address is derived from the last 20 bytes of the Keccak-256 hash.

```javascript
const ethereumAddress = wallet.address
```

{% code title="Ethereum Address" %}

```
0x3872E96F79890737fCf74aa85D6d760a5a451Fe9
```

{% endcode %}


# Ethereum State Explained

In Ethereum, the entire state of the blockchain, including all accounts and smart contracts, can be thought of as a part of a large, shared state database. Each contract has its own storage, but it's not exactly like a "mapping within a mapping." Let's break this down:

### Ethereum's Global State

* Ethereum's blockchain can be conceptualized as a state machine, where the state includes all accounts (both externally owned accounts and contract accounts) and their balances, nonce, bytecode, and storage (for contract accounts).
* This state is stored in a key-value store (the Ethereum Virtual Machine's state), where each key is an address (20 bytes), and the value is the account's state.

### Contract Storage

* Each smart contract on Ethereum has its own storage space, identified by its contract address. This storage is separate for each contract.
* A contract's storage is a key-value store where both the key and value are 256 bits wide. In this storage, state variables of the contract are stored.
* The way Solidity organizes these storage slots for a contract's state variables is deterministic and follows specific rules, but from the Ethereum protocol's perspective, it just sees a key-value store for each contract.

### Analogy with Mappings

* If we use the analogy of mappings, Ethereum's global state is like a huge mapping where each key is an account address, and the value is the account's state (including a contract's code and storage).
* Within each contract, the storage can be thought of as another mapping, where the keys are essentially the storage slots (sequential for simple variables, computed through hashing for complex types like arrays and mappings) and the values are the contents of those slots.

### Interactions and Independence

* Each contract's storage is independent of others. When a contract is executed, it can only access its own storage directly (though it can call other contracts and trigger changes in their storage through these calls).
* The Ethereum blockchain maintains the integrity and isolation of each contract's storage. This means that a contract cannot directly access or modify the storage of another contract unless explicitly programmed to do so through defined interfaces and function calls.

In summary, Ethereum's state is a large, shared state database, with each contract having its own isolated storage space. This storage space can be conceptualized as a key-value store, unique to each contract, where the contract's state variables are stored.


# Gas Fees Explained

### Gas Limit

Gas limit refers to the maximum amount of gas you are willing to consume on a transaction. More complicated transactions involving smart contracts require more computational work, so they require a higher gas limit than a simple payment. A standard ETH transfer requires a gas limit of 21,000 units of gas.

For example, if you put a gas limit of 50,000 for a simple ETH transfer, the EVM would consume 21,000, and you would get back the remaining 29,000. However, if you specify too little gas, for example, a gas limit of 20,000 for a simple ETH transfer, the EVM will consume your 20,000 gas units attempting to fulfill the transaction, but it will not complete. The EVM then reverts any changes, but since the validator has already done 20k gas units worth of work, that gas is consumed.

{% hint style="info" %}
The gas limit is like the distance you want to travel in a car. E.g. if my journey is 21km away (a standard transfer) then I must have at minimum 21km worth of gas in my car. If I get to the destination without using the whole tank of gas (because I specified a higher limit than I needed) then I get to keep the gas in the car (ETH gets refunded to my wallet).
{% endhint %}

### Max Fee

{% hint style="info" %}
Max Fee is the maximum amount you are willing to pay for the gas at the pump at the start of the journey. So if you don't mind when you start the journey (e.g. the middle of the night) then you can wait until gas is cheap, and your journey will only start when the max fee lowers to your desired amount (transaction will only be picked up at that point, but not necessarily executed because of... Max Priority Fee).
{% endhint %}

### Max Priority Fee

{% hint style="info" %}
Once gas reaches the price you want to pay for your journey, at that point there might be a long queue at the gas station for you to fill up, and while you're waiting in line the price could go up again! So a priority fee is like a bribe/tip you pay to the pump attendant to fill up your car first before anyone else.
{% endhint %}

### Max Transaction Fee

If you are buying 21,000 units of gas, and you set a `max fee` to limit the maximum amount you will pay, then the validator will pocket the difference from the base fee, up to the `max priority fee` set. So, if I want to buy 21,000 units of gas, and I set a `max fee` of 50 Gwei and a `max priority fee` of 5 Gwei, then if the `base fee` at the time of the transaction is:

* 47 Gwei then the validator will earn the 3 Gwei.
  * But if 3 Gwei isn't a high enough fee compared with other transactions then I'll be left out.
* 45 Gwei then the validator will earn the maximum 5 Gwei.
  * Again, only if 5 is enough of a tip to beat other people in the same block.
* 40 Gwei then the validator will still only earn a maximum of 5 Gwei as that's the limit I set and any difference will be returned to the senders wallet.
  * This returned amount will be a messy number.


# Useful Tools


# Ethers

How to use a custom struct in Ethers

```solidity
struct UpgradeHistory {
    string version;
    uint256 upgradeTime;
    address upgradeInitiator;
}
```

{% code fullWidth="true" %}

```javascript
const aavePMAbi = [
    "function getUpgradeHistory() external view returns (tuple(string version, uint256 upgradeTime, address upgradeInitiator)[] memory)",
    ]
    
const upgradeHistoryData = await aavePM.getUpgradeHistory()
aavePMData.upgradeHistory = upgradeHistoryData.map((item) => ({
    version: item.version,
    upgradeTime: BigNumber(item.upgradeTime).toNumber(),
    upgradeInitiator: item.upgradeInitiator,
}))


{aavePMData?.upgradeHistory
    ?.sort((b, a) => a.upgradeTime - b.upgradeTime)
    .map((upgrade, index) => (
        <UpgradeDisplay
            key={index}
            version={upgrade.version}
            upgradeTime={upgrade.upgradeTime}
            upgradeInitiator={upgrade.upgradeInitiator}
        />
))}
```

{% endcode %}


# Ethernal

{% embed url="<https://tryethernal.com/>" %}

Ethernal is like Etherscan for your own private Ethereum chain. This makes it perfect for smart contract development!

It can be run completely locally, but their hosted UI works well.

## Create a Workspace

[https://app.tryethernal.com](https://app.tryethernal.com/)

## Import Contract Addresses

Useful for ERC20 token addresses.

* Enter an address of a contract deployed on Ethereum mainnet.
* If the contract has been verified on Etherscan, its name, and ABI will be pulled automatically.
* If not, the contract will be imported but you'll have to manually add the name and ABI.
* To be able to use this, your workspace needs to be connected to a mainnet fork. If it is not, the contract will still be imported but calls will fail.

<figure><img src="/files/J1Bxx2hAuGnMGEIWifE4" alt=""><figcaption></figcaption></figure>

## CLI Tool

This CLI tool exports transaction data and contract ABIs to the Ethernal UI automatically.&#x20;

<https://github.com/tryethernal/ethernal-cli>

```bash
npm install ethernal -g
```

Set the ETHERNAL\_API\_TOKEN in the `.env` and then use it like this as it doesn't seem to work any other way.

```bash
source .env
ETHERNAL_API_TOKEN=${ETHERNAL_API_TOKEN} ethernal listen
```

## UI - Add proxy read/write field

This code snippet adds a `Proxy Address` field to the `Read/Write` tab on a contract.

* If the contract is accessed via a proxy, input the proxy address to read and write via that proxy address.
* If left blank, it will use the current contract address

<figure><img src="/files/wtP81O376MP1sX21Fuis" alt=""><figcaption></figcaption></figure>

### Install Tampermonkey Chrome app

{% embed url="<https://chromewebstore.google.com/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo>" %}

* Enable `Developer mode` for extensions to allow Tampermonkey to work: <https://www.tampermonkey.net/faq.php#Q209>

### Tampermonkey Script

{% code fullWidth="true" %}

```javascript
// ==UserScript==
// @name         Modify Ethereum Network Requests with Dynamic Proxy
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Intercept and modify Ethereum contract calls with a dynamic proxy address
// @author       EridianAlpha
// @match        https://app.tryethernal.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    console.log("Tampermonkey script for modifying fetch requests loaded.");

    let inputPlaced = false;

    // Function to inject an input field
    const injectInputField = () => {
        const interactionsDiv = document.getElementById("interactions");
        if (interactionsDiv) {
            if (!inputPlaced) {
                const label = document.createElement("label");
                label.textContent = "PROXY ADDRESS";
                label.style.display = "block";
                label.style.marginBottom = "5px";
                label.style.color = "gray";
                label.style.margin = "10px 10px 0px 12px";
                label.style.fontSize = "small";
                label.style.fontWeight = "bold";

                const input = document.createElement("input");
                input.id = "tampermonkey-proxy-address";
                input.type = "text";
                input.placeholder = "Proxy address...";
                input.style.margin = "2px 10px 10px 12px";
                input.style.border = "1px solid gray";
                input.style.padding = "8px";
                input.style.minWidth = "500px";
                input.style.borderRadius = "5px";

                interactionsDiv.insertBefore(label, interactionsDiv.firstChild);
                interactionsDiv.insertBefore(input, label.nextSibling);

                inputPlaced = true;
            }
        } else {
            inputPlaced = false;
        }
    };

    // Check for the interactions div
    const checkDivInterval = setInterval(injectInputField, 500);


    // Store the original fetch
    const originalFetch = window.fetch;

    // Define a new fetch
    window.fetch = async function(resource, init) {
        // Check for proxy address in the input field
        const proxyInput = document.getElementById("tampermonkey-proxy-address");
        const proxyAddress = proxyInput && proxyInput.value;

        if (proxyAddress) {
            console.log("Proxy address in use:", proxyAddress);
            // Fetch modification logic
            if (init && init.method === "POST" && typeof init.body === "object" && !Array.isArray(init.body) && init.body !== null) {
            // Convert the body object to a string
                let bodyString = Object.keys(init.body).sort((a, b) => a - b).map(key => String.fromCharCode(init.body[key])).join('');
                let requestData;
                try {
                    requestData = JSON.parse(bodyString);
                } catch (e) {
                    console.error("Error parsing fetch request data:", e);
                    return originalFetch(resource, init);
                }

                if (requestData.method === "eth_call" || requestData.method === "eth_sendTransaction") {
                    console.log("Tampermonkey script: Modifying fetch request data.");
                    requestData.params[0].to = proxyAddress; // Change to your proxy address
                    init.body = JSON.stringify(requestData);
                    console.log("Modified fetch data:", JSON.stringify(requestData));
                }
            }
        } else {
            console.log("No proxy address found - using this contract address");
        }

        // Call the original fetch with modified or unmodified arguments
        return originalFetch(resource, init);
    };
})();
```

{% endcode %}


# Solidity Notes


# Interview Questions

{% content-ref url="/pages/2qLy56hqQyJk7xg5HWpQ" %}
[1. Easy - Interview Questions](/ethereum-dev/solidity-notes/interview-questions/1.-easy-interview-questions)
{% endcontent-ref %}

{% content-ref url="/pages/QGz2KXa54XA2Ugmgtl5d" %}
[2. Medium - Interview Questions](/ethereum-dev/solidity-notes/interview-questions/2.-medium-interview-questions)
{% endcontent-ref %}

{% content-ref url="/pages/9U3FAYa9OZ28yTuxuiXS" %}
[3. Hard - Interview Questions](/ethereum-dev/solidity-notes/interview-questions/3.-hard-interview-questions)
{% endcontent-ref %}

{% content-ref url="/pages/XjRdcCrVn7k2xK4dkxEe" %}
[4. Advanced - Interview Questions](/ethereum-dev/solidity-notes/interview-questions/4.-advanced-interview-questions)
{% endcontent-ref %}


# 1. Easy - Interview Questions

{% embed url="<https://www.rareskills.io/post/solidity-interview-questions>" %}

### 1.1. What is the difference between private, internal, public, and external functions?

A `private` function is only accessible inside the contract in which it is defined. An `internal` function function is only accessible inside the contract in which it is defined AND inherited contracts. An `external` function is intended to be called from outside the contract in which it is defined but can be called by using `this.<FUNCTION_NAME>()`. It's used to reduce gas costs rather than to actually stop it from being called by the current contract. A `public` function is callable by anyone, anywhere.

### 1.2. Approximately, how large can a smart contract be?

Ethereum enforces a maximum contract size of 24 KB (24,576 bytes) for the bytecode of deployed contracts. This limit is meant to prevent overly large contracts from consuming excessive blockchain resources and ensure efficient validation and execution. Deploying a smart contract must fit within the block gas limit, which varies but is typically around 30 million gas on Ethereum mainnet.

E.g. A contract could have a deployed bytecode size of less than 24 KB but still use more than the block gas limit if it had complex logic in its constructor which is executed during deployment.

### 1.3. What is the difference between create and create2?

The `CREATE` opcode creates a contract at an address determined by the deployer nonce. So it is possible to know the address in advance but only if you know what the the deployer nonce will be at the time of deployment.

`CREATE2` opcode allows contracts to be deployed at a specific address derived from:

* The deployer’s address.
* A salt value (a 32-byte arbitrary value provided by the deployer).
* The keccak256 hash of the contract’s bytecode.

### 1.4. What major change with arithmetic happened with Solidity 0.8.0?

Over and underflow checks were added by default. The compiler now automatically reverts the transaction if an arithmetic operation results in an overflow or underflow. This enhancement makes contracts more secure by default and reduces the need for external libraries like SafeMath for these checks which were needed in previous versions.

### 1.5. What special CALL is required for proxies to work?

`delegatecall()` is used to preserve the context of a call, which is a requirement for proxy contracts.

### 1.6. How do you calculate the dollar cost of an Ethereum transaction?

Find the gas cost of the tx and multiply it by the price of Ethereum as the time of the tx.

### 1.7. What are the challenges of creating a random number on the blockchain?

A blockchain is inherently deterministic. To achieve consensus on the state of a blockchain, every node must be able to come to the same output for a given set of inputs. Therefore, true random number generation is not possible and external sources of randomness are required e.g. oracles.

### 1.8. What is the difference between a Dutch Auction and an English Auction?

A Dutch auction starts with a high price that decreases incrementally until a buyer accepts the current price, leading to a quicker sale at the first bid. In contrast, an English auction begins at a low starting price and increases with competitive bids until no higher offers are made, allowing bidders to actively compete for the highest price. The Dutch auction is faster and can prevent bidding wars, while the English auction encourages competition and transparency in price discovery.

### 1.9. What is the difference between transfer and transferFrom in ERC20?

In the ERC20 standard, `transfer` allows a token holder to send tokens directly to another address, reducing the balance of the sender and increasing the balance of the recipient. `transferFrom` facilitates token transfers on behalf of a third party, requiring prior approval via `approve` for the spender to move a specified number of tokens from the owner’s account. This makes `transferFrom` useful for use cases like escrow services or delegated transfers where a contract or user acts on behalf of another.

### 1.10. Which is better to use for an address allowlist: a mapping or an array?

Mapping. A mapping allows constant-time (O(1)) lookups and is much more efficient for regular checks like allowlists. If a user is on the allowlist, simply set their address value in the mapping to be `true` and it will be fast and gas efficient to check. To check if a user is in an array, the entire array may need to be processed, which means that the gas costs of interacting with the contract will grow exponentially with the size of the allow list array.

### 1.11. Why shouldn’t tx.origin be used for authentication?

If a contract uses `tx.origin` to authenticate an address then it is vulnerable to being manipulated by a malicious man-in-the-middle contract. If a malicious contract can pass through the `tx.origin` then it could call a function e.g. an NFT transfer, without the explicit consent of the owner. This is why `msg.sender` is more secure as the context is the address of the contract that directly called the function, unless `delegatecall()` has been used.

### 1.12. What hash function does Ethereum primarily use?

keccak256. This is a variant of the SHA-3 family but differs slightly from the finalized NIST standard version of SHA-3. The keccak256 function is used in various core aspects of Ethereum, such as generating addresses, creating unique identifiers, and verifying data integrity within smart contracts.

### 1.13. How much is 1 gwei of Ether? How much is 1 wei of Ether?

`1 Gwei = 0.000000001 ETH`

`1 Wei = 0.000000000000000001 ETH`

[https://eth-converter.com](https://eth-converter.com/)

### 1.14. What is the difference between assert and require?

`require` is used to validate conditions that are expected to be true under normal circumstances, such as function input validation or checking contract state. It is typically used for user input, contract interaction conditions, and external calls. If the condition fails, `require` will revert the transaction and return any remaining gas to the caller. `require` can include a custom error message that is returned when the condition fails, making it easier to debug and understand why the transaction reverted.

`assert` is used to test for internal errors and invariants within the code that should never fail. It checks conditions that, if broken, indicate a bug in the contract. Unlike `require`, `assert` is used to validate assumptions that should always hold true in contract logic. If an `assert` statement fails, it consumes all the gas provided for the transaction. `assert` does not provide an error message, so debugging is more difficult. It is meant for cases where a failure indicates a severe bug.

### 1.15. What is a flash loan?&#x20;

A flash loan is a function offered by lending platforms like Aave that allows anyone to borrow a huge amount of funds, at a fixed interest rate, for a single tx. The only condition is that the borrowed tokens + interest must be returned within the same tx it is borrowed, or the whole tx will revert. Flash loans are a powerful financial primitive not found in traditional financial markets and allow anyone to exploit financial opportunities, even when starting with almost no capital.

> Anyone can be a whale for 12 seconds.

### 1.16. What is the check-effects-interaction pattern?

The check-effects-interaction pattern in Solidity enforces an order to prevent reentrancy vulnerabilities and unexpected outcomes. All checks and verifications should happen first, and then all effects that make changes to the state of the current smart contract should be actioned. Finally, only when those first two steps have been completed should the function interact with external contracts and/or users.

### 1.17. What is the minimum amount of Ether required to run a solo staking node?

32 ETH.

### 1.18. What is the difference between fallback and receive?

```solidity
 /**
  * Explainer from: https://solidity-by-example.org/fallback
  * ETH is sent to contract
  *      is msg.data empty?
  *           /    \
  *         yes    no
  *         /       \
  *    receive()?  fallback()
  *      /     \
  *    yes     no
  *    /        \
  * receive()  fallback()
  */
```

### 1.19. What is reentrancy?

When an external call in a function allows for another function to be called before expected state changes have been made. E.g. A send funds function that sends ETH before updating a user's balance. When the ETH is sent, the call to that user could be to a contract, which would allow for its receive or fallback function to reenter the calling contract and trigger the sending function again.

### 1.20. What prevents infinite loops from running forever?

30 million gas block limit on Ethereum mainnet. Even on L2s with higher gas limits still would reach a limit that stops loops from running forever. A caller would also run out of ETH to pay for gas even before the gas limit is reached.

### 1.21. What is the difference between tx.origin and msg.sender?

`tx.origin` is the original source of the tx, the Externally Owned Account (EOA). `msg.sender` is the address of the direct caller of the current function, so in a chain of contract calls, only the final contract that calls the function would show as `msg.sender`.

### 1.22. How do you send Ether to a contract that does not have payable functions, or a receive or fallback?

`selfdestruct()` no longer deletes the code of a contract once deployed, but currently during deployment, if `selfdestruct()` is called it can be used to force sent ETH.

### 1.23. What is the difference between view and pure?

View functions can view the state of the blockchain. Pure functions cannot view any state and can only manipulate data passed to them.

### 1.24. What is the difference between transferFrom and safeTransferFrom in ERC721?

`transferFrom` transfers ownership of an NFT from one address to another without performing additional checks. It does not verify whether the recipient address is a contract or a regular address. If you use transferFrom to send an NFT to a smart contract that doesn’t handle ERC721 tokens, the token could be “stuck” since the contract might not have a way to process it.

`safeTransferFrom` ensures a safe transfer by performing an additional check when sending an NFT to a contract address. It calls onERC721Received on the recipient contract if it’s a contract, ensuring that the contract is aware of the incoming NFT and can handle it properly. If the recipient contract does not implement the required onERC721Received function, the transaction will revert, preventing the NFT from being “stuck” in a contract that can’t process it.

### 1.25. How can an ERC1155 token be made into a non-fungible token?

In the ERC1155 standard, tokens are inherently semi-fungible, meaning they can be fungible or non-fungible based on how they’re defined. To create a non-fungible token (NFT) within an ERC1155 contract, you can treat specific token IDs as unique, which gives them non-fungible properties.

### 1.26. What is an access control and why is it important?

Modifers are useful for standardizing ownership and role-based checks on functions. Common access controls are `onlyOwner`.

### 1.27 What does a modifier do?

A modifier in Solidity is a keyword that defines reusable code to be run either before or after a function’s main logic, depending on the placement of the `_;` statement within the modifier. Modifiers are flexible, allowing you to add functionality to functions in a modular, organized way.

### 1.28. What is the largest value a uint256 can store?

{% code fullWidth="true" %}

```bash
chisel

type(uint256).max

Type: uint256
├ Hex: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
├ Hex (full word): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
└ Decimal: 115792089237316195423570985008687907853269984665640564039457584007913129639935
```

{% endcode %}


# 2. Medium - Interview Questions

{% embed url="<https://www.rareskills.io/post/solidity-interview-questions>" %}

### 2.1 What is the difference between transfer and send?

* `send`
  * Returns a bool indicating success (true) or failure (false).
  * Only forwards a fixed 2300 gas stipend, which is often enough for basic operations but might not suffice for complex logic in the receiving contract.
  * If the transfer fails, it does not revert the transaction. You need to handle the failure by checking the return value.
* `transfer`
  * Automatically reverts the transaction if the transfer fails, so no additional error handling is needed.
  * Also forwards a fixed 2300 gas stipend, preventing the receiving contract from executing too much code.
  * Generally considered safer because it reverts on failure, meaning you don’t have to manually check for success.

### 2.2 Why should they not be used?

Due to the fixed gas limits, they are not flexible enough to work with smart contract wallets which may require more gas than is available from `transfer` or `send`.

### 2.3 What is a storage collision in a proxy contract?

When a function in the proxy contract has the same 4-byte identifier as a function in the implementation contract. This will cause a collision and mean that the function in the implementation contract can never be called.

### 2.4 What is the difference between abi.encode and abi.encodePacked?

* `abi.encode`
  * Encodes data in ABI (Application Binary Interface) encoding format.
  * Adds padding to make each data item fit into a 32-byte slot, following the ABI encoding standards.
  * Each argument is encoded as a standalone item, with proper padding and alignment, which makes it more readable and less error-prone when used in conjunction with other Solidity functions.
  * Example:&#x20;
    * Input: `bytes memory encodedData = abi.encode("Hello", uint256(123));`
    * Output (encodedData): `0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000` (padded to 32 bytes).
* `abi.encodePacked`
  * Encodes data in a compact, non-standard format.
  * Does not add padding, so each data item is placed directly after the previous one without any alignment.
  * Generally used for more compact encoding or for concatenating data, such as when creating a unique hash (e.g., in keccak256 hashing).
  * **Be careful with potential collisions**:
    * Concatenating variable-length types (like string and bytes) without padding can result in ambiguous results. For example, encoding two strings with abi.encodePacked("abc", "def") and abi.encodePacked("ab", "cdef") would produce the same output.
  * Example:
    * Input: `bytes memory packedData = abi.encodePacked("Hello", uint256(123));`
    * Output (packedData): `0x48656c6c6f000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000` (no padding).

### 2.5 uint8, uint32, uint64, uint128, uint256 are all valid uint sizes. Are there others?

### 2.6 What changed with block.timestamp before and after proof of stake?

### 2.7 What is frontrunning?

### 2.8 What is a commit-reveal scheme and when would you use it?

### 2.9 Under what circumstances could abi.encodePacked create a vulnerability?

### 2.10 How does Ethereum determine the BASEFEE in EIP-1559?

### 2.11 What is the difference between a cold read and a warm read?

Cold reads happen when a storage slot is read for the first time during a transaction call. Cold reads are more expensive in terms of gas because the storage slot is being loaded into memory from disk.

Warm reads are for each subsequent call and have a lower gas cost than the initial cold read. The gas cost is lower for warm reads because the storage slot is already loaded into memory, eliminating the need for the more expensive disk access.

This distinction was introduced with EIP-2929 (Ethereum Berlin Hardfork) to make gas costs better reflect the computational effort required for storage access.

### 2.12 How does an AMM price assets?

### 2.13 What is a function selector clash in a proxy and how does it happen?

A function selector clash in a proxy contract occurs when a function in the proxy contract has the same function selector as a function in the implementation contract. Since the proxy handles calls before they reach the implementation, if the proxy defines a function with the same selector as one in the implementation, the proxy function will always take precedence, preventing the implementation function from ever being called.

### 2.14 What is the effect on gas of making a function payable?

### 2.15 What is a signature replay attack?

When a signature is reused multiple times, this could occur on the same chain or across different chains. Signature replay attacks can be mitigated by specifying a nonce to stop a signature from being used twice on the same chain, as well as a chain identifier so that the signature is only valid on the chain it was intended to be used on.

### 2.16 How would you design a game of rock-paper-scissors in a smart contract such that players cannot cheat?

### 2.17 What is the free memory pointer and where is it stored?

`0x40`

### 2.18 What function modifiers are valid for interfaces?

Only `external`is a valid modifier for interfaces.

### 2.19 What is the difference between memory and calldata in a function argument?

### 2.20 Describe the three types of storage gas costs for writes.

### 2.21 Why shouldn’t upgradeable contracts use the constructor?

A constructor is run the first time a contract is deployed, but as an implementation contract stores its state on the proxy contract, any actions that occur in the constructor of the implementation contract would act in the context of that implementation contract.

This would lead to unexpected and unintended consequences, so this is why a initializer is used for upgradeable contracts instead of the constructor.

### 2.22 What is the difference between UUPS and the Transparent Upgradeable Proxy pattern?

### 2.23 If a contract delegatecalls an empty address or an implementation that was previously self-destructed, what happens?

In both cases, the call fails, returns false, and reverts if `require(success)` is used.

### 2.24 What if it is a low-level call instead of a delegatecall?

### 2.25 What danger do ERC777 tokens pose?

They implement a callback mechanism that has the potential to allow reentrancy attacks.

### 2.26 According to the solidity style guide, how should functions be ordered?

### 2.27 According to the solidity style guide, how should function modifiers be ordered?

### 2.28 What is a bonding curve?

### 2.29 How does \_safeMint differ from \_mint in the OpenZeppelin ERC721 implementation?

### 2.30 What keywords are provided in Solidity to measure time?

* 1 == 1 seconds
* 1 minutes == 60 seconds
* 1 hours   == 60 \* 60 seconds
* 1 days    == 24 \* 60 \* 60 seconds
* 1 weeks   == 7 \* 24 \* 60 \* 60 seconds

```solidity
uint deadline = block.timestamp + 3 days;
```

### 2.31 What is a sandwich attack?

### 2.32 If a delegatecall is made to a function that reverts, what does the delegatecall do?

### 2.33 What is a gas efficient alternative to multiplying and dividing by a power of two?

### 2.34 How large a uint can be packed with an address in one slot?

### 2.35 Which operations give a partial refund of gas?

### 2.36 What is ERC165 used for?

### 2.37 If a proxy makes a delegatecall to A, and A does address(this).balance, whose balance is returned, the proxy’s or A?

### 2.38 What is a slippage parameter useful for?

### 2.39 What does ERC721A do to reduce mint costs? What is the tradeoff?

### 2.40 Why doesn’t Solidity support floating point arithmetic?

**1. Determinism and Precision:** Solidity operates in a decentralized environment where all computations must produce identical results across all nodes. Floating-point arithmetic is prone to rounding errors and imprecision due to the way computers represent real numbers, which could lead to inconsistencies in transaction outcomes.

**2. Gas Costs:** Implementing floating-point operations would increase the computational complexity and gas costs, as these operations require additional processing for handling precision, rounding, and edge cases. This inefficiency makes them impractical for the EVM.

### 2.41 What is TWAP? How does Compound Finance calculate utilization?

### 2.42 If a delegatecall is made to a function that reads from an immutable variable, what will the value be?

If a delegatecall is made to a function that reads from an immutable variable, the value returned will be garbage (invalid data) or potentially zero, depending on the context. This happens because immutable variables are stored in the code section of the contract that defines them, and delegatecall does not change the code context.

This issue is specific to immutable variables. It does not apply to constant variables or hardcoded values.

### 2.43 What is a fee-on-transfer token?

### 2.44 What is a rebasing token?

### 2.45 In what year will a timestamp stored in a uint32 overflow?

For signed integers, it will be the year [2038](https://computer.fandom.com/wiki/Time_formatting_bugs#Year_2028).

For unsigned 32-bit integers, it will be the year [2106](https://computer.fandom.com/wiki/Time_formatting_bugs#Year_2106).

### 2.46 What is LTV in the context of DeFi?

### 2.47 What are aTokens and cTokens in the context of Compound Finance and AAVE?

### 2.48 Describe how to use a lending protocol to go leveraged long or leveraged short on an asset.

### 2.49 What is a perpetual protocol?


# 3. Hard - Interview Questions

{% embed url="<https://www.rareskills.io/post/solidity-interview-questions>" %}

All of these questions can be answered in three sentences or less.

### 3.1 How does fixed point arithmetic represent numbers?

Fixed-point arithmetic represents numbers using a fixed number of bits for the integer and fractional parts. Unlike floating-point arithmetic, which dynamically adjusts precision, fixed-point numbers maintain a constant scaling factor.

### 3.2 What is an ERC20 approval frontrunning attack?

### 3.3 What opcode accomplishes address(this).balance?

```
BALANCE
```

### 3.4 How many arguments can a solidity event have?

17 total arguments of which 3 can be  indexed parameters.

* Indexed parameters are stored in the event’s topics
* The remaining parameters are stored in the event’s data field in the transaction logs.

### 3.5 What is an anonymous Solidity event?

An event declared with the `anonymous keyword`. This means that it does not have a topic for the event signature, making it more gas-efficient but harder to filter in logs.

* No topic for the event signature, making it cheaper to emit.
* All parameters can be indexed, unlike regular events.

```solidity
event MyEvent(address indexed user, uint256 amount) anonymous; 

function emitEvent() external {
    emit MyEvent(msg.sender, 100);
}
```

**Why Use Anonymous Events?**

✅ Lower Gas Cost – Saves gas by omitting the event signature topic.

✅ Index More Parameters – Can index all parameters instead of just 3.

**When NOT to Use Anonymous Events?**

❌ Harder to Filter in Logs – Since there’s no event signature topic, you must filter logs by indexed parameters only.

❌ Less Readable for External Indexers – Standard logs rely on event signatures for indexing, so anonymous events make it harder to track events externally.

### 3.6 Under what circumstances can a function receive a mapping as an argument?

A function can receive a mapping as an argument only if it’s an internal or private function. This is because mappings are not iterable or passable as values due to their storage-bound nature.

### 3.7 What is an inflation attack in ERC4626?

### 3.8 How many storage slots does this use? uint64\[] x = \[1,2,3,4,5]? Does it differ from memory?&#x20;

### 3.9 Prior to the Shanghai upgrade, under what circumstances is returndatasize() more efficient than PUSH 0?

### 3.10 Why does the compiler insert the INVALID op code into Solidity contracts?

The INVALID opcode (also known as 0xFE) is an explicit way for the EVM to halt execution immediately and consume all remaining gas. Solidity compilers insert INVALID in contracts for various reasons, primarily to prevent unintended execution paths and ensure correctness in smart contracts.

1. Unreachable Code Protection
2. Function Selectors for Nonexistent Functions
3. Error Handling in Jump Tables
4. Preventing Uninitialized Storage Corruption

### 3.11 What is the difference between how a custom error and a require with error string is encoded at the EVM level?

### 3.12 1hat is the kink parameter in the Compound DeFi formula? 1ow can the name of a function affect its gas cost, if at all?

### 3.13 What is a common vulnerability with ecrecover?

### 3.14 What is the difference between an optimistic rollup and a zk-rollup?

### 3.15 How does EIP1967 pick the storage slots, how many are there, and what do they represent?

### 3.16 How much is one Sazbo of ether?

### 3.17 What can delegatecall be used for besides use in a proxy?

### 3.18 Under what circumstances would a smart contract that works on Etheruem not work on Polygon or Optimism? (Assume no dependencies on external contracts)

### 3.19 How can a smart contract change its bytecode without changing its address?

### 3.20 What is the danger of putting msg.value inside of a loop?

### 3.21 escribe the calldata of a function that takes a dynamic length array of uint128 when uint128\[1,2,3,4] is passed as an argument.

### 3.22 Why is strict inequality comparisons more gas efficient than ≤ or ≥? What extra opcode(s) are added?

### 3.23 If a proxy calls an implementation, and the implementation self-destructs in the function that gets called, what happens?

### 3.24What is the relationship between variable scope and stack depth?

### 3.25What is an access list transaction?

### 3.26 How can you halt an execution with the mload opcode?

### 3.27 What is a beacon in the context of proxies?

### 3.28 Why is it necessary to take a snapshot of balances before conducting a governance vote?

### 3.29 How can a transaction be executed without a user paying for gas?

### 3.30 In solidity, without assembly, how do you get the function selector of the calldata?

### 3.31 How is an Ethereum address derived?

### 3.32 What is the metaproxy standard?

### 3.33 If a try catch makes a call to a contract that does not revert, but a revert happens inside the try block, what happens?

### 3.34 If a user calls a proxy makes a delegatecall to A, and A makes a regular call to B, from A’s perspective, who is msg.sender? from B’s perspective, who is msg.sender? From the proxy’s perspective, who is msg.sender?

### 3.35 Under what circumstances do vanity addresses (leading zero addresses) save gas?

### 3.36 Why do a significant number of contract bytecodes begin with 6080604052?

### 3.37 What does that bytecode sequence do?

### 3.38 How does Uniswap V3 determine the boundaries of liquidity intervals?

### 3.39 What is the risk-free rate?

### 3.40 When a contract calls another call via call, delegatecall, or staticcall, how is information passed between them?

### 3.41 What is the difference between bytes and bytes1\[]?

### 3.42 What is the most amount of leverage that can be achieved in a borrow-swap-supply-collateral loop if the LTV is 75%? What about other LTV limits?

### 3.43 How does Curve StableSwap achieve concentrated liquidity?

### 3.44 What quirks does the Tether stablecoin contract have?

### 3.45 What is the smallest uint that will store 1 million? 1 billion? 1 trillion? 1 quadrillion?

### 3.46 What danger to uninitialized UUPS logic contracts pose?

### 3.47 What is the difference (if any) between what a contract returns if a divide-by-zero happens in Soliidty or if a divide-by-zero happens in Yul?

### 3.48 Why can’t .push() be used to append to an array in memory?


# 4. Advanced - Interview Questions

{% embed url="<https://www.rareskills.io/post/solidity-interview-questions>" %}

All of these questions can be answered in three sentences or less.

### 4.1 What addresses to the ethereum precompiles live at?

### 4.2 Describe what “liquidity” is in the context of Uniswap V2 and Uniswap V3.

### 4.3 If a delegatecall is made to a contract that makes a delegatecall to another contract, who is msg.sender in the proxy, the first contract, and the second contract?

### 4.4 What is the difference between how a uint64 and uint256 are abi-encoded in calldata?

### 4.5 What is read-only reentrancy?

### 4.6 What are the security considerations of reading a (memory) bytes array from an untrusted smart contract call?

### 4.7 If you deploy an empty Solidity contract, what bytecode will be present on the blockchain, if any?

### 4.8 How does the EVM price memory usage?

### 4.9 What is stored in the metadata section of a smart contract?

### 4.10 What is the uncle-block attack from an MEV perspective?

### 4.11 How do you conduct a signature malleability attack?

### 4.12 Under what circumstances do addresses with leading zeros save gas and why?

### 4.13 What is the difference between payable(msg.sender).call{value: value}("") and msg.sender.call{value: value}("")?

### 4.14 How many storage slots does a string take up?

### 4.15 How does the --via-ir functionality in the Solidity compiler work?

### 4.16 Are function modifiers called from right to left or left to right, or is it non-deterministic?

### 4.17 If you do a delegatecall to a contract and the opcode CODESIZE executes, which contract size will be returned?

### 4.18 Why is it important to ECDSA sign a hash rather than an arbitrary bytes32?

### 4.19 Describe how symbolic manipulation testing works.

### 4.20 What is the most efficient way to copy regions of memory?

### 4.21 How can you validate on-chain that another smart contract emitted an event, without using an oracle?

### 4.22 When selfdestruct is called, at what point is the Ether transferred? At what point is the smart contract’s bytecode erased?

### 4.23 Under what conditions does the Openzeppelin Proxy.sol overwrite the free memory pointer? Why is it safe to do this?

### 4.24 Why did Solidity deprecate the “years” keyword?

### 4.25 What does the verbatim keyword do, and where can it be used?

### 4.26 How much gas can be forwarded in a call to another smart contract?

### 4.27 What does an int256 variable that stores -1 look like in hex?

### 4.28 What is the use of the signextend opcode?

### 4.29 Why do negative numbers in calldata cost more gas?

### 4.30 What is a zk-friendly hash function and how does it differ from a non-zk-friendly hash function?

### 4.31 What does a metaproxy do?

### 4.32 What is a nullifier in the context of zero knowledge, and what is it used for?

### 4.33 What is SECP256K1?

### 4.34 Why shouldn’t you get price from slot0 in Uniswap V3?

### 4.35 Describe how to compute the 9th root of a number on-chain in Solidity.

### 4.36 What is the danger of using return in assembly out of a Solidity function that has a modifier?

### 4.37 Without using the % operator, how can you determine if a number is even or odd?

### 4.38 What does codesize() return if called within the constructor? What about outside the constructor?


# Note Ideas

* <https://twitter.com/apoorvlathey/status/1726229244593004905>
* `abi.encodePacked`&#x20;
  * Write out what it does and how it's similar/same as string.concat
  * [abi.encodePacked](/ethereum-dev/solidity-notes/abi.encodepacked)


# ABI

* <https://coinsbench.com/solidity-tutorial-all-about-abi-46da8b517e7>
* <https://blog.ricmoo.com/human-readable-contract-abis-in-ethers-js-141902f4d917>

{% embed url="<https://github.com/EridianAlpha/ethereum-direct-deploy-contract>" %}

### ABI with ethers.js

* <https://docs.ethers.io/v4/api-contract.html>

```solidity
// Contract ABI copied directly from Remix
let abi = [
    {
        inputs: [],
        name: "consecutiveWins",
        outputs: [
            {
                internalType: "uint256",
                name: "",
                type: "uint256",
            },
        ],
        stateMutability: "view",
        type: "function",
    },
]

let coinFlipContractAddress = "0xa0714D4539ADcfD7855B811382c49D7185D32977"

// Connect to the Contract
let coinFlipContract = new ethers.Contract(
    coinFlipContractAddress,
    abi,
    rinkebyHttpProvider
)

// Check current consecutiveWins value
let consecutiveWins = await coinFlipContract.consecutiveWins()
```


# abi.encodePacked

* <https://github.com/PatrickAlphaC/hardhat-nft-fcc/tree/main/contracts/sublesson>
* <https://blog.openzeppelin.com/deconstructing-a-solidity-contract-part-i-introduction-832efd2d7737>


# Abstract Contracts

* <https://docs.soliditylang.org/en/v0.8.16/contracts.html#abstract-contracts>
* Contracts must be marked as abstract when at least one of their functions is not implemented or when they do not provide arguments for all of their base contract constructors
* Even if this is not the case, a contract may still be marked abstract, such as when you do not intend for the contract to be created directly
* Abstract contracts are similar to Interfaces but an interface is more limited in what it can declare.<br>
* An abstract contract is declared using the abstract keyword as shown in the following example
* Note that this contract needs to be defined as abstract, because the function utterance() is declared, but no implementation was provided (no implementation body { } was given)

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

abstract contract Fruit {
    function color() public pure virtual returns (bytes32);
}

contract Apple is Fruit {
    function color() public pure override returns (bytes32) { return "green"; }
}
```


# Arrays

There are two types of arrays in Solidity:

* Fixed arrays
* Dynamic arrays

```solidity
// Array with a fixed length of 2 elements:
uint[2] fixedArray;

// another fixed Array, can contain 5 strings:
string[5] stringArray;

// a dynamic Array - has no fixed size, can keep growing:
uint[] dynamicArray;
```

You can also create an array of structs:

```
People[] public people; // dynamic Array, we can keep adding to it
```

Remember that state variables are stored permanently in the blockchain. So creating a dynamic array of structs like this can be useful for storing structured data in your contract, kind of like a database.

{% hint style="info" %}
Strings are an array of bytes, which means they can't be directly compared.
{% endhint %}

### Public Arrays

You can declare an array as public, and Solidity will automatically create a getter method for it. The syntax looks like:

```solidity
struct People {
  uint age;
  string name;
}

People[] public people;
```

### Working with Arrays

Create new `People` and add them to our `people` array.

```solidity
// Create a new Person:
People satoshi = People(172, "Satoshi");

// Add that person to the Array:
people.push(satoshi);
```

We can also combine these together and do them in one line of code to keep things clean:

```solidity
people.push(Person(16, "Vitalik"));
```

Note that `array.push()` adds something to the end of the array, so the elements are in the order we added them. See the following example:

```solidity
uint[] numbers;
numbers.push(5);
numbers.push(10);
numbers.push(15);
// numbers is now equal to [5, 10, 15]
```

### Example

* <https://solidity-by-example.org/array/>

{% code fullWidth="false" %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Array {
    // Several ways to initialize an array
    uint[] public arr;
    uint[] public arr2 = [1, 2, 3];
    // Fixed sized array, all elements initialize to 0
    uint[10] public myFixedSizeArr;

    function get(uint i) public view returns (uint) {
        return arr[i];
    }

    // Solidity can return the entire array.
    // But this function should be avoided for arrays that 
    // can grow indefinitely in length.
    function getArr() public view returns (uint[] memory) {
        return arr;
    }

    function push(uint i) public {
        // Append to array
        // This will increase the array length by 1.
        arr.push(i);
    }

    function pop() public {
        // Remove last element from array
        // This will decrease the array length by 1
        arr.pop();
    }

    function getLength() public view returns (uint) {
        return arr.length;
    }

    function remove(uint index) public {
        // Delete does not change the array length.
        // It resets the value at index to it's default value,
        // in this case 0
        delete arr[index];
    }

    function examples() external {
        // create array in memory, only fixed size can be created
        uint[] memory a = new uint[](5);
    }
}
```

{% endcode %}

### Examples - Removing array element

* <https://solidity-by-example.org/array/>

{% code fullWidth="false" %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract ArrayReplaceFromEnd {
    uint[] public arr;

    // Deleting an element creates a gap in the array.
    // One trick to keep the array compact is to
    // move the last element into the place to delete.
    function remove(uint index) public {
        // Move the last element into the place to delete
        arr[index] = arr[arr.length - 1];
        // Remove the last element
        arr.pop();
    }

    function test() public {
        arr = [1, 2, 3, 4];

        remove(1);
        // [1, 4, 3]
        assert(arr.length == 3);
        assert(arr[0] == 1);
        assert(arr[1] == 4);
        assert(arr[2] == 3);

        remove(2);
        // [1, 4]
        assert(arr.length == 2);
        assert(arr[0] == 1);
        assert(arr[1] == 4);
    }
}
```

{% endcode %}


# Casting

Any casting operation from a higher-bit accuracy to a lower-bit accuracy can result in data loss of the upper bits that have been removed.

It is always advisable to perform these type casts safely, ensuring that the data being cast will fit to the expected type under all circumstances.

<figure><img src="/files/isQiiC8ZK5swzy0a0Ny3" alt=""><figcaption><p><a href="https://twitter.com/Omniscia_sec/status/1757091772402938345">https://twitter.com/Omniscia_sec/status/1757091772402938345</a></p></figcaption></figure>


# CEI - Checks, Effects, Interactions

Helps to avoid reentrancy and different types of attacks

* Checks
  * Check the criteria for the function
* Effects
  * Changes to the current contract
* Interactions
  * Changes to other contracts

{% tabs %}
{% tab title="Explained" %}
Great StackOverflow answer: <https://ethereum.stackexchange.com/a/56995/106466>

**❌ Intuitive approach:**

1. Interact with a contract
2. Check the result.
3. Do something with the result.

**✅ Safe way:**

1. Optimistically deal with state changes (accounting) - assume success.
2. Interact with the contract.
3. Revert changes from step 1 if needed (`.transfer()`) does it automatically. `revert()` is an option, or manually return all values to their previous values in the unlikely event that you want to continue.

It may help to separate contracts into two categories: Those you trust and those you can't be certain about.

There is nothing wrong with, and you often can't avoid calling `view` and `pure` functions in your own system (trusted) and there is nothing wrong with that. You may also want to call `view` functions in other people's contracts that may be suspect - they have made it upgradable, for example, so there is no way ensure the interaction will always be safe even if you see the code today.

Given that those untrusted contracts may themselves inspect the state of *your* contract, there is a possibility of re-entrant class of exploits. A solution to that problem is to ensure that your state is completely in order before you transfer flow control to the untrusted contract. In other words, don't give them a chance to inspect a half-baked, incomplete transaction in progress because they invoke other functions in your contract or might return with an unexpected result your contract isn't prepared for.

In essence, put your guards up front and gather all the info you will need (checks). Record the complete update to your own state, including the expected results of the final steps, e.g. zero out a balance (effects). Lastly, state-changing operations in other "untrusted" contracts such as `send`, `transfer` or `call`. Notice if it failed and revert your state changes in that case.
{% endtab %}
{% endtabs %}


# Comments (NATSPEC)

* <https://docs.soliditylang.org/en/v0.8.16/natspec-format.html>

### Tags

All tags are optional. The following table explains the purpose of each NatSpec tag and where it may be used. As a special case, if no tags are used then the Solidity compiler will interpret a `///` or `/**` comment in the same way as if it were tagged with `@notice`.

<table data-full-width="true"><thead><tr><th width="189.33333333333331">Tag</th><th width="451">Description</th><th>Context</th></tr></thead><tbody><tr><td><code>@title</code></td><td>A title that should describe the contract/interface</td><td>contract, library, interface</td></tr><tr><td><code>@author</code></td><td>The name of the author</td><td>contract, library, interface</td></tr><tr><td><code>@notice</code></td><td>Explain to an end user what this does</td><td>contract, library, interface, function, public state variable, event</td></tr><tr><td><code>@dev</code></td><td>Explain to a developer any extra details</td><td>contract, library, interface, function, state variable, event</td></tr><tr><td><code>@param</code></td><td>Documents a parameter just like in Doxygen (must be followed by parameter name)</td><td>function, event</td></tr><tr><td><code>@return</code></td><td>Documents the return variables of a contract’s function</td><td>function, public state variable</td></tr><tr><td><code>@inheritdoc</code></td><td>Copies all missing tags from the base function (must be followed by the contract name)</td><td>function, public state variable</td></tr><tr><td><code>@custom:...</code></td><td>Custom tag, semantics is application-defined</td><td>everywhere</td></tr></tbody></table>


# Constructor

* A constructor is an optional function that is executed upon contract creation.

{% hint style="info" %}
No functions, including the `receive()` function, can be invoked from logic in the constructor. Only logic and calls inside the constructor will execute as expected.

An unexpected consequence of this is if a call is made in the constructor that results in ETH being sent to the `receive()` function, as the ETH does get received, but the logic in the `receive()` function doesn't execute.
{% endhint %}

### Example

* <https://solidity-by-example.org/constructor/>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Base contract X
contract X {
    string public name;

    constructor(string memory _name) {
        name = _name;
    }
}

// Base contract Y
contract Y {
    string public text;

    constructor(string memory _text) {
        text = _text;
    }
}

// There are 2 ways to initialize parent contract with parameters.

// Pass the parameters here in the inheritance list.
contract B is X("Input to X"), Y("Input to Y") {

}

contract C is X, Y {
    // Pass the parameters here in the constructor,
    // similar to function modifiers.
    constructor(string memory _name, string memory _text) X(_name) Y(_text) {}
}

// Parent constructors are always called in the order of inheritance
// regardless of the order of parent contracts listed in the constructor of the child contract.

// Order of constructors called:
// 1. X
// 2. Y
// 3. D
contract D is X, Y {
    constructor() X("X was called") Y("Y was called") {}
}

// Order of constructors called:
// 1. X
// 2. Y
// 3. E
contract E is X, Y {
    constructor() Y("Y was called") X("X was called") {}
}
```


# Contract Structure & Versions

### Code License

* Specify a license at the top of every file.

```solidity
// SPDX-License-Identifier: MIT
```

### Solidity Versions

{% code fullWidth="false" %}

```solidity
pragma solidity 0.8.7;              // A specific version
pragma solidity ^0.8.7;             // Version 0.8.7 or higher
pragma solidity >=0.8.7 <0.9.0;     // Only versions including or greater than 0.8.7 
                                    // and less than 0.9.0
```

{% endcode %}

### Contract Template

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract HelloWorld {
}
```

### Import

* When you have multiple files and you want to import one file into another, Solidity uses the `import`keyword:

```solidity
import "./someothercontract.sol";

contract newContract is SomeOtherContract {
}
```

* So if we had a file named `someothercontract.sol` in the same directory as this contract (that's what the `./`means), it would get imported by the compiler.
* Imports can also be renamed when being imported:

```solidity
import {WETH9Test as Handler} from "./WETH9Test.t.sol";

contract WETH9TestInvariant is Test, Counter {

    Handler public handler;

    function setUp() public {
        handler = new Handler();
    }
}
```

### Contract Layout

* license
* version
* imports
* errors
* interfaces, libraries, contracts
* type declarations
* state variables
* events
* modifiers
* functions

### Function Layout

* constructor
* receive function (if exists)
* fallback function (if exists)
* external
* public
* internal
* private
* view & pure functions


# Data - Storage vs Memory

{% @github-files/github-code-block %}

### Data Locations

The EVM can access and store information in six places:

1. Stack
2. Memory
   * Temporary variables that can be modified
3. Storage
   * Permanent variables that can be modified
4. Calldata
   * Temporary variables that can't be modified
5. Code
6. Logs

Data locations can only be specified for types:

* Array
  * Strings
* Struct
* Mapping

{% hint style="info" %}
**A location specifier is not needed for `unit` as Solidity knows that it will be `memory`**
{% endhint %}

### Calldata

* The variable only exists temporarily and can't be modified
* Similar to memory, but use `calldata` instead of `memory` if you don't plan on changing the variable
* `calldata` variable values can't be reassigned

### Storage vs Memory

In Solidity, there are two locations where you can store variables — in `storage`and in `memory`.

* `storage` refers to variables stored permanently on the blockchain.
* `memory` variables are temporary, and are erased between external function calls to your contract. Think of it like your computer's hard disk vs RAM.

Usually, these keywords aren't needed because Solidity handles them by default. State variables (variables declared outside of functions) are by default `storage` and written permanently to the blockchain, while variables declared inside functions are `memory` and will disappear when the function call ends.

However, there are times when you do need to use these keywords, namely when dealing with structs and arrays within functions:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SandwichFactory {
  struct Sandwich {
    string name;
    string status;
  }

  Sandwich[] sandwiches;

  function eatSandwich(uint _index) public {
    // Sandwich mySandwich = sandwiches[_index];

    // ^ Seems pretty straightforward, but solidity will give you a warning
    // telling you that you should explicitly declare `storage` or `memory` here.

    // So instead, you should declare with the `storage` keyword, like:
    Sandwich storage mySandwich = sandwiches[_index];
    // ...in which case `mySandwich` is a pointer to `sandwiches[_index]`
    // in storage, and...
    mySandwich.status = "Eaten!";
    // ...this will permanently change `sandwiches[_index]` on the blockchain.

    // If you just want a copy, you can use `memory`:
    Sandwich memory anotherSandwich = sandwiches[_index + 1];
    // ...in which case `anotherSandwich` will simply be a copy of the 
    // data in memory, and...
    anotherSandwich.status = "Eaten!";
    // ...will just modify the temporary variable and have no effect 
    // on `sandwiches[_index + 1]`. But you can do this:
    sandwiches[_index + 1] = anotherSandwich;
    // ...if you want to copy the changes back into blockchain storage.
  }
}
```

* The Solidity compiler will give warnings to let you know when you should be using one of these keywords.
* Understand that there are cases where you'll need to explicitly declare `storage` or `memory`.

### Storage is Expensive

* One of the more expensive operations in Solidity is using `storage` — particularly writes.
* This is because every time you write or change a piece of data, it’s written permanently to the blockchain. Forever! Thousands of nodes across the world need to store that data on their hard drives, and this amount of data keeps growing over time as the blockchain grows. So there's a cost to doing that.
* In order to keep costs down, you want to avoid writing data to storage except when absolutely necessary. Sometimes this involves seemingly inefficient programming logic — like rebuilding an array in `memory`every time a function is called instead of simply saving that array in a variable for quick lookups.
* In most programming languages, looping over large data sets is expensive. But in Solidity, this is way cheaper than using `storage` if it's in an `external view`function, since `view` functions don't cost your users any gas. (And gas costs your users real money!).

### Declaring arrays in memory

* You can use the `memory` keyword with arrays to create a new array inside a function without needing to write anything to storage. The array will only exist until the end of the function call, and this is a lot cheaper gas-wise than updating an array in `storage` — free if it's a `view` function called externally.
* Here's how to declare an array in memory:

```solidity
function getArray() external pure returns(uint[] memory) {
  // Instantiate a new array in memory with a length of 3
  uint[] memory values = new uint[](3);

  // Put some values to it
  values[0] = 1;
  values[1] = 2;
  values[2] = 3;

  return values;
}
```

{% hint style="info" %}
`memory` arrays must be created with a length argument (in this example, 3). They currently cannot be resized like `storage` arrays can with `array.push()`, although this may be changed in a future version of Solidity.
{% endhint %}

### Example

* <https://solidity-by-example.org/data-locations/>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

contract DataLocations {
    uint[] public arr;
    mapping(uint => address) map;
    struct MyStruct {
        uint foo;
    }
    mapping(uint => MyStruct) myStructs;

    function f() public {
        // call _f with state variables
        _f(arr, map, myStructs[1]);

        // get a struct from a mapping
        MyStruct storage myStruct = myStructs[1];
        // create a struct in memory
        MyStruct memory myMemStruct = MyStruct(0);
    }

    function _f(
        uint[] storage _arr,
        mapping(uint => address) storage _map,
        MyStruct storage _myStruct
    ) internal {
        // do something with storage variables
    }

    // You can return memory variables
    function g(uint[] memory _arr) public returns (uint[] memory) {
        // do something with memory array
    }

    function h(uint[] calldata _arr) external {
        // do something with calldata array
    }
}
```


# Data - Storage Layout

In Ethereum, all values in storage, whether they represent numbers, addresses, or array lengths, are stored as 32-byte hexadecimal values.

## **256-bit Address Space**

* In Ethereum, each smart contract has a storage space that can be thought of as a large array of 32-byte (256-bit) slots.
* This means there are `2^256` possible storage slots, each capable of holding 32 bytes of data.

## **Storage Slots**

* Each storage slot is 32 bytes (256 bits).
* Simple variables (e.g., uint256, address) typically occupy a single slot.
  * A `uint256` is 32 bytes so perfectly fills an entire slot.
  * An `address` is 20 bytes but still takes up a whole storage slot.
    * The remaining 12 bytes (96 bits) in the slot are padded with zeros.
  * A `bool` only requires 1 bit, it still occupies a full slot of 32 bytes, with 31 bytes padded with zeros.
* Complex data structures (e.g., mappings, arrays) utilize multiple slots, often determined by hash functions.

## Simple Variables

* Simple variables like `uint256`, `address`, `bool` occupy one storage slot.
* The slot index is determined by the order of declaration in the contract.

## Mappings

* Hash-Based Slot Calculation.
* Mappings are stored using a hash of the key and the slot number as the storage location.
* For a mapping `mapping(uint256 => uint256)`, the storage slot for a key `k` is `keccak256(abi.encodePacked(k, p))`, where `p` is the slot number of the mapping itself.
* E.g for a mapping 5 => 99 at mapping slot 3 the storage slot of the value would be
  * `keccak256(abi.encodePacked(5, 3))` is the slot storing 99
* A mapping doesn't have an empty storage slot to show it's a mapping, it has an empty storage slot because it needs the slot number to be able to calculate where it stored the values, and there's nothing to actually store in the slot.

## Arrays

* Static arrays have a base slot, and elements are stored in consecutive slots starting from that base slot. Each element occupies a full 32-byte storage slot, regardless of its actual size.
* Dynamic arrays store their length in the base slot, and elements are stored starting from `keccak256(baseSlot)`.

{% code fullWidth="true" %}

```solidity
uint256[3] public fixedArray; // Base slot, e.g., slot 0, 1, 2
uint256[] public dynamicArray; // Length at slot 1, elements at keccak256(1), keccak256(1)+1, ...
```

{% endcode %}

## Optimizing Storage with Packing

Solidity can pack multiple small variables into a single slot if they fit within the 32-byte limit and are declared consecutively. This is known as "storage packing."

```solidity
contract PackedStorage {
    uint128 public myUint128;       // Uses the first 16 bytes of slot 0
    uint128 public mySecondUint128; // Uses the next 16 bytes of slot 0
    uint64 public myUint64;         // Uses the first 8 bytes of slot 1
    uint64 public mySecondUint64;   // Uses the next 8 bytes of slot 1
    uint32 public myUint32;         // Uses the next 4 bytes of slot 1
    uint32 public mySecondUint32;   // Uses the next 4 bytes of slot 1
    uint32 public myThirdUint32;    // Uses the next 4 bytes of slot 1
    uint32 public myFourthUint32;   // Uses the next 4 bytes of slot 1
}
```

Storage packing can lead to significant gas savings by minimizing the number of storage slots used. However, care must be taken with the order of declaration to achieve optimal packing.

When you access a packed variable, Solidity automatically handles the correct segment of the storage slot. For example, if you access `myUint64`, Solidity retrieves the bytes 0-7 from slot 1 and interprets them as a `uint64`.

## Empty Slots and Interpretation

* Unused storage slots default to zero.
* There is no inherent indicator within the slot itself to distinguish whether it is an unused slot or a slot belonging to a mapping that has not been assigned a value yet.
* It is the responsibility of the compiler and the ABI to interpret storage correctly.
* The contract's bytecode and ABI contain the necessary information to differentiate between different types of storage (e.g., simple variables, arrays, mappings).

## Storage Example

{% @github-files/github-code-block %}

* <https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html>&#x20;
* Each storage slot is `32 bytes` long and represents the bytes version of the object

{% hint style="info" %}
Constants and immutable variables are not in storage and don't take up a storage slot, as they are considered part of the bytecode of the contract.
{% endhint %}

{% code fullWidth="true" %}

```solidity
[0] 0x00...19       <--    uint256 favoriteNumber = 25;         // Hex representation of 25 (0x19)
[1] 0x00...01       <--    bool someBool = true;                // Hex value of 1 for true (0x1)
[2] 0x00...01       <--    uint256[] dynamicArray;              // Storage slot only contains array length in hex (0x1)
[3] 0x00...0E       <--    uint256[2] fixedArray = [14,15];     // Stoage of item 0 in fixedArray (0xE)
[4] 0x00...0F       <--                                         // Stoage of item 1 in fixedArray (0xF)
[5] 0x00...00       <--    mapping(address => uint256) public balances  // Empty storage slot since it's a mapping (0x0)
...

// DYNAMIC ARRAYS
// Storage locations for data in array myArray from storage slot [2]
    // 2 is the slot number containing the length
    // i is the index of the array item (not used for push as it just gets added to the end of the array)
[keccak256(2)]      <--    myArray.push(222);
[keccak256(2) + i]  <--    myArray[i];

// MAPPINGS
// Storage locations for data in mapping balances from storage slot [3]
    // 3 is the slot where `balances` is stored
    // 0x123... is the mapping key (an address in this example)
[keccak256(abi.encode(0x123..., 3))]    <-- balances[0x123...]
```

{% endcode %}


# Enum

* Solidity supports enumerables and they are useful to model choice and keep track of state.
* Enums can be declared outside of a contract.

### Example

* <https://solidity-by-example.org/enum/>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Enum {
    // Enum representing shipping status
    enum Status {
        Pending,
        Shipped,
        Accepted,
        Rejected,
        Canceled
    }

    // Default value is the first element listed in
    // definition of the type, in this case "Pending"
    Status public status;

    // Returns uint
    // Pending  - 0
    // Shipped  - 1
    // Accepted - 2
    // Rejected - 3
    // Canceled - 4
    function get() public view returns (Status) {
        return status;
    }

    // Update status by passing uint into input
    function set(Status _status) public {
        status = _status;
    }

    // You can update to a specific enum like this
    function cancel() public {
        status = Status.Canceled;
    }

    // delete resets the enum to its first value, 0
    function reset() public {
        delete status;
    }
}
```

### Declaring and Importing Enum

* File that the enum is declared in.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// This is saved 'EnumDeclaration.sol'

enum Status {
    Pending,
    Shipped,
    Accepted,
    Rejected,
    Canceled
}
```

* File that imports the enum above.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./EnumDeclaration.sol";

contract Enum {
    Status public status;
}
```


# Errors (require & revert)

* An error will undo all changes made to the state during a transaction.
* You can throw an error by calling `require`, `revert` or `assert`.

{% hint style="info" %}
Great article explaining how Solidity reverts, custom errors, and try/catch work:

<https://www.rareskills.io/post/try-catch-solidity>
{% endhint %}

### require

* Used to validate inputs and conditions before execution.

```solidity
// Used in both test contracts and main contracts
require(success, "Call failed"); 
```

### revert

* Similar to require, revert is useful when the condition to check is complex.
* So put it at the end of a longer logic statement making it easier to read.

```solidity
// This error definition is needed in the main contract and the test contract
error FundMe__RefundFailed();

// In main contract
if (!callSuccess) revert FundMe__RefundFailed();

// In test contract
// Expects the next line to revert with the specified error
vm.expectRevert(FundMe__RefundFailed.selector);
testHelper.fundMeRefund();
```

* The `.selector` property retrieves the unique identifier (selector) of the `FundMe__RefundFailed` error.
* In the case of errors (and events), the selector is derived from the error's name and its parameters.

### assert

```solidity
// Used in both test contracts and main contracts
assert(funders.length == 3);
assertEq(funders.length, 3); // More informative logs
```

### Gas Saving

```solidity
error FundMe__NotOwner();

// Uses more gas as a custom error is stored as a string (bytes array)
require(msg.sender == i_owner);

// Uses less gas as the error is not stored as a string
if (msg.sender != i_owner) revert FundMe__NotOwner();
```

### Example

* <https://solidity-by-example.org/error/>

{% code title="Example 1" %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Error {
    function testRequire(uint _i) public pure {
        // Require should be used to validate conditions such as:
        // - inputs
        // - conditions before execution
        // - return values from calls to other functions
        require(_i > 10, "Input must be greater than 10");
    }

    function testRevert(uint _i) public pure {
        // Revert is useful when the condition to check is complex.
        // This code does the exact same thing as the example above
        if (_i <= 10) {
            revert("Input must be greater than 10");
        }
    }

    uint public num;

    function testAssert() public view {
        // Assert should only be used to test for internal errors,
        // and to check invariants.

        // Here we assert that num is always equal to 0
        // since it is impossible to update the value of num
        assert(num == 0);
    }

    // Custom error with multiple parameters
    error InsufficientBalance(uint balance, uint withdrawAmount);

    function testCustomError(uint _withdrawAmount) public view {
        uint bal = address(this).balance;
        if (bal < _withdrawAmount) {
            revert InsufficientBalance({balance: bal, withdrawAmount: _withdrawAmount});
        }
    }
}
```

{% endcode %}

{% code title="Example 2" %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Account {
    uint public balance;
    uint public constant MAX_UINT = 2**256 - 1;

    function deposit(uint _amount) public {
        uint oldBalance = balance;
        uint newBalance = balance + _amount;

        // balance + _amount does not overflow if balance + _amount >= balance
        require(newBalance >= oldBalance, "Overflow");

        balance = newBalance;

        assert(balance >= oldBalance);
    }

    function withdraw(uint _amount) public {
        uint oldBalance = balance;

        // balance - _amount does not underflow if balance >= _amount
        require(balance >= _amount, "Underflow");

        if (balance < _amount) {
            revert("Underflow");
        }

        balance -= _amount;

        assert(balance <= oldBalance);
    }
}
```

{% endcode %}


# Events

Events are a way for your contract to communicate that something happened on the blockchain to your app front-end, which can be 'listening' for certain events and taking action when they happen.

{% hint style="info" %}
It's best practice to have events emitted before the "Interactions" section of your function (in the [CEI model](/ethereum-dev/solidity-notes/cei-checks-effects-interactions)).
{% endhint %}

* You can have up to 3 `indexed parameters` (also know as `topics`) per individual event.
* Event logs can't be accessed by smart contracts, so are only used for off-chain applications such as web apps.

```solidity
contract SimpleStorage {
    uint256 favoriteNumber;
    event StoredNumber(
        uint256 indexed oldNumber,
        uint256 indexed newNumber,
        uint256 addedNumber,
        address sender
    );

    function store(uint256 _favoriteNumber) public {
        emit StoredNumber(
            favoriteNumber,
            _favoriteNumber,
            _favoriteNumber + favoriteNumber,
            msg.sender
        );
        favoriteNumber = _favoriteNumber;
    }

    function retrieve() public view returns (uint256) {
        return favoriteNumber;
    }
}
```


# EVM Opcodes

View all EVM Opcodes: [https://www.evm.codes](https://www.evm.codes/)

Decompile bytecode to opcodes: <https://www.evm.codes/playground>


# External Contract Interaction

If a dependency contract had a bug it would render our DApp completely useless — our DApp would point to a hardcoded address that no longer returns the expected result and we'd be unable to modify our contract to fix it.

For this reason, it often makes sense to have functions that will allow you to update key portions of the DApp.

For example, instead of hard coding the contract address into our DApp, we should probably have a setExternalContractAddress function that lets us change this address in the future in case something happens to the external contract being used.

```solidity
ExternalContractInterface externalContract;

function setExternalContractAddress(address _address) external {
    externalContract = ExternalContractInterface(_address);
}
```


# External Dependencies


# Functions

## Function Types

<table><thead><tr><th width="179">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>non-constant</code></td><td><ul><li>The default function type and doesn't get specified as a <a href="/pages/zIABtb11ZkD6UnKVMG6v">modifier</a>.</li><li>The function can modify the state of the contract on the blockchain. Non-constant functions can write to the contract's storage, emit events, create other contracts, and use <code>selfdestruct</code>.</li></ul></td></tr><tr><td><code>view</code></td><td><ul><li>Doesn't cost gas when called directly (externally by a user).</li><li>Does cost gas when called by another function or contract.</li><li>Reads the state of the blockchain but can't modify it.</li></ul></td></tr><tr><td><code>pure</code></td><td><ul><li>Doesn't cost gas when called directly.</li><li>Does cost gas when called by another function or contract.</li><li>Does not read the state of the blockchain, only memory and calldata.</li></ul></td></tr></tbody></table>

## Selector and Signature

```solidity
// Example Function Selector:
0xa9059cbb

// Example Function Signature:
"transfer(address,uint256)"
```

## Code Conventions

* Function parameters and private function names start with an underscore `_`

```solidity
uint[] numbers;

function _addToArray(uint _number) private {
  numbers.push(_number);
}
```

## Visibility Specifiers

* Info
  * <https://docs.soliditylang.org/en/v0.8.13/cheatsheet.html#function-visibility-specifiers>
  * <https://medium.com/@yangnana11/solidity-function-types-4ad4e5de6d56>
* Variables default to `internal` if no visibility specifier is given
* State variables can be declared as `public`, `private`, or `internal` but not `external`
  * <https://solidity-by-example.org/visibility/>

<table data-full-width="true"><thead><tr><th width="141">Visibility</th><th>Description</th></tr></thead><tbody><tr><td><code>internal</code></td><td><ul><li>Default visibility specifier when none are specified.</li><li>Internal functions can only be called inside the current contract (more specifically, inside the current code unit, which also includes internal library functions and inherited functions) because they cannot be executed outside of the context of the current contract.</li><li>Calling an internal function is realized by jumping to its entry label, just like when calling a function of the current contract internally.</li><li>Those functions and state variables can only be accessed internally (i.e. from within the current contract or contracts deriving from it), without using <code>this</code>.</li></ul></td></tr><tr><td><code>external</code></td><td><ul><li>External functions consist of an address and a function signature and they can be passed via and returned from external function calls.</li><li>Can be called from outside, can’t be called from inside (functions from same contract, functions from inherited contracts).</li><li>External functions are part of the contract interface, which means they can be called from other contracts and via transactions.</li><li>An external function <code>f</code> cannot be called internally (i.e. <code>f()</code> does not work, but <code>this.f()</code> works).</li><li>External functions are sometimes more efficient when they receive large arrays of data.</li></ul></td></tr><tr><td><code>private</code></td><td><ul><li>Private functions can only be called from inside the current contract, even the inherited contracts can’t call them.</li><li>Private functions and state variables are only visible for the contract they are defined in and not in derived contracts.</li></ul></td></tr><tr><td><code>public</code></td><td><ul><li>Public functions can be called from anywhere.</li><li>Public functions are part of the contract interface and can be either called internally or via messages.</li><li>For public state variables, an automatic getter function is generated.</li></ul></td></tr></tbody></table>

### Function Declarations

A function declaration in Solidity looks like the following:

```solidity
function eatHamburgers(string memory _name, uint _amount) public {
}
```

This is a function named `eatHamburgers` that takes 2 parameters: a string and a uint. For now the body of the function is empty. Note that we're specifying the function visibility as public. We're also providing instructions about where the `_name` variable should be stored in memory. This is required for all reference types such as `arrays`, `structs`, `mappings`, and `strings`.

What is a reference type you ask? Well, there are two ways in which you can pass an argument to a Solidity function:

* By value, which means that the Solidity compiler creates a new copy of the parameter's value and passes it to your function. This allows your function to modify the value without worrying that the value of the initial parameter gets changed.
* By reference, which means that your function is called with a... reference to the original variable. Thus, if your function changes the value of the variable it receives, the value of the original variable gets changed.

{% hint style="info" %}
It's convention (but not required) to start function parameter variable names with an underscore (\_) in order to differentiate them from global variables.
{% endhint %}

You would call this function like so:

```
eatHamburgers("vitalik", 100);
```

### Private / Public functions

{% hint style="warning" %}
In Solidity, functions are `public` by default. This means anyone (or any other contract) can call your contract's function and execute its code.
{% endhint %}

Obviously, this isn't always desirable and can make your contract vulnerable to attacks. Thus it's good practice to make all functions `private`, and then only make `public` the functions you want to expose to the world.

Let's look at how to declare a private function:

```solidity
uint[] numbers;

function _addToArray(uint _number) private {
  numbers.push(_number);
}
```

This means only other functions within our contract will be able to call this function and add to the `numbers`array.

As you can see, we use the keyword `private`after the function name.

{% hint style="info" %}
It's convention to start private function names with an underscore `_`.
{% endhint %}

### Internal and External functions

In addition to `public` and `private`, Solidity has two more types of visibility for functions:

* `internal`
  * Similar `private`, except that it's also accessible to contracts that inherit from this contract.
* `external`
  * Similar to `public`, except that these functions can ONLY be called outside the contract — they can't be called by other functions inside that contract.
  * For declaring internal or external functions, the syntax is the same as private and public:

```solidity
contract Sandwich {
  uint private sandwichesEaten = 0;

  function eat() internal {
    sandwichesEaten++;
  }
}

contract BLT is Sandwich {
  uint private baconSandwichesEaten = 0;

  function eatWithBacon() public returns (string memory) {
    baconSandwichesEaten++;
    // We can call this here because it's internal
    eat();
  }
}
```

## Free Functions

Functions can be defined inside and outside of contracts.

Functions outside of a contract, also called “[free functions](https://docs.soliditylang.org/en/latest/contracts.html#functions)”, always have implicit `internal` visibility. Their code is included in all contracts that call them, similar to internal library functions.

```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.1 <0.9.0;

function sum(uint[] memory arr) pure returns (uint s) {
    for (uint i = 0; i < arr.length; i++)
        s += arr[i];
}

contract ArrayExample {
    bool found;
    function f(uint[] memory arr) public {
        // This calls the free function internally.
        // The compiler will add its code to the contract.
        uint s = sum(arr);
        require(s >= 10);
        found = true;
    }
}
```

{% hint style="info" %}
Functions defined outside a contract are still always executed in the context of a contract. They still can call other contracts, send them Ether and destroy the contract that called them, among other things. The main difference to functions defined inside a contract is that free functions do not have direct access to the variable `this`, storage variables and functions not in their scope.
{% endhint %}

## Function Input Parameters

* If a function requires an input parameter for the function to be valid (e.g. for an override) but you don't actually use the parameter in the function, it can be commented out.

```solidity
function checkUpkeep( bytes memory /* checkData */ ) public view override
    returns (bool upkeepNeeded, bytes memory /* performData */)
{
    // Function content...
}
```

## Handling Multiple Return Values

This `getKitty` function is the first example we've seen that returns multiple values. Let's look at how to handle them:

```solidity
function multipleReturns() internal returns(uint a, uint b, uint c) {
  return (1, 2, 3);
}

function processMultipleReturns() external {
  uint a;
  uint b;
  uint c;
  // This is how you do multiple assignment:
  (a, b, c) = multipleReturns();
}

// Or if we only cared about one of the values:
function getLastReturnValue() external {
  uint c;
  // We can just leave the other fields blank:
  (,,c) = multipleReturns();
}
```

## Example

* <https://solidity-by-example.org/function/>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

contract Function {
    // Functions can return multiple values.
    function returnMany()
        public
        pure
        returns (
            uint,
            bool,
            uint
        )
    {
        return (1, true, 2);
    }

    // Return values can be named.
    function named()
        public
        pure
        returns (
            uint x,
            bool b,
            uint y
        )
    {
        return (1, true, 2);
    }

    // Return values can be assigned to their name.
    // In this case the return statement can be omitted.
    function assigned()
        public
        pure
        returns (
            uint x,
            bool b,
            uint y
        )
    {
        x = 1;
        b = true;
        y = 2;
    }

    // Use destructuring assignment when calling another
    // function that returns multiple values.
    function destructuringAssignments()
        public
        pure
        returns (
            uint,
            bool,
            uint,
            uint,
            uint
        )
    {
        (uint i, bool b, uint j) = returnMany();

        // Values can be left out.
        (uint x, , uint y) = (4, 5, 6);

        return (i, b, j, x, y);
    }

    // Cannot use map for either input or output

    // Can use array for input
    function arrayInput(uint[] memory _arr) public {}

    // Can use array for output
    uint[] public arr;

    function arrayOutput() public view returns (uint[] memory) {
        return arr;
    }
}
```


# Function Modifiers

## view / pure

When a function doesn't actually change state in Solidity — e.g. it doesn't change any values or write anything we could declare it as a `view`function, meaning it's only viewing the data but not modifying it:

```solidity
pragma solidity ^0.8.0;

contract GreetingContract {
    string private greeting;

    constructor() {
        greeting = "Hello, World!";
    }

    function sayHello() public view returns (string memory) {
        return greeting;
    }
}
```

Solidity also contains `pure`functions, which means you're not even accessing any data in the app. Consider the following:

```solidity
function _multiply(uint a, uint b) private pure returns (uint) {
    return a * b;
}
```

This function doesn't even read from the state of the app — its return value depends only on its function parameters. So in this case we would declare the function as `pure`.

## Ownable Contracts

Below is the `Ownable` contract taken from the `OpenZeppelin` Solidity library. OpenZeppelin is a library of secure and community-vetted smart contracts that you can use in your own DApps.

* <https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.1/contracts/access/Ownable.sol>

{% code fullWidth="true" %}

```solidity
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
```

{% endcode %}

The `Ownable`contract does the following:

1. When a contract is created, its constructor sets the `Ownable` to `msg.sender`(the person who deployed it).
2. It adds an `onlyOwner` modifier, which can restrict access to certain functions to only the `Ownable`.
3. It allows you to transfer the contract to a new `Ownable`.

`onlyOwner` is such a common requirement for contracts that most Solidity DApps start with a copy/paste or import of this `Ownable` contract, and then their first contract inherits from it.

## Function Modifiers - Generic

A function modifier looks just like a function, but uses the keyword `modifier` instead of the keyword `function`. And it can't be called directly like a function can — instead we can attach the modifier's name at the end of a function definition to change that function's behavior.

Let's take a closer look by examining `onlyOwner` (see code extract above)

* Notice the `onlyOwner` modifier on the `renounceOwnership` function.
* When you call `renounceOwnership`, the code inside `onlyOwner` executes first.&#x20;
* Then when it hits the `_;`statement in `onlyOwner`, it goes back and executes the code inside renounceOwnership.
* While there are other ways you can use modifiers, one of the most common use-cases is to add a quick require check before a function executes.
* In the case of onlyOwner, adding this modifier to a function makes it so only the owner of the contract (you, if you deployed it) can call that function.

{% hint style="info" %}
Giving the owner special powers over the contract like this is often necessary, but it could also be used maliciously. For example, the owner could add a backdoor function.
{% endhint %}

* Modifiers can all be stacked together on a function definition.
* Modifiers are executed in the order they are listed in the function declaration.

```solidity
function test() external view onlyOwner anotherModifier { /* ... */ }
```

1. First, the logic inside the `onlyOwner` modifier is executed. This modifier typically checks whether the caller of the function is the owner of the contract.
2. After `onlyOwner` completes its execution, `anotherModifier` is executed next. The specific logic of this modifier depends on its implementation.
3. Finally, if all modifiers execute successfully (i.e., none of them revert), the body of the `test` function is executed.

## Function Modifiers with Arguments

Function modifiers can also take arguments.

```solidity
// A mapping to store a user's age:
mapping (uint => uint) public age;

// Modifier that requires this user to be older than a certain age:
modifier olderThan(uint _age, uint _userId) {
  require(age[_userId] >= _age);
  _;
}

// Must be older than 16 to drive a car (in the US, at least).
// We can call the `olderThan` modifier with arguments like so:
function driveCar(uint _userId) public olderThan(16, _userId) {
  // Some function logic
}
```

* You can see here that the `olderThan` modifier takes arguments just like a function does.
* And that the `driveCar` function passes its arguments to the modifier.

## Payable Modifier

`payable`functions are a special type of function that can receive ETH.

* This allows for some really interesting logic, like requiring a certain payment to the contract in order to execute a function.

```solidity
contract OnlineStore {
  function buySomething() external payable {
    // Check to make sure 0.001 ether was sent to the function call:
    require(msg.value == 0.001 ether);
    // If so, some logic to transfer the digital item to the caller of the function:
    transferThing(msg.sender);
  }
}
```

* Here, `msg.value`is a way to see how much ETH was sent to the contract, and ether is a built-in unit.
* What happens here is that someone would call the function from web3.js (from the DApp's JavaScript front-end) as follows:

{% code overflow="wrap" %}

```javascript
// Assuming `OnlineStore` points to your contract on Ethereum:
OnlineStore.buySomething({from: web3.eth.defaultAccount, value: web3.utils.toWei(0.001)})
```

{% endcode %}

* Notice the `value`field, where the javascript function call specifies how much ether to send (0.001).
* If you think of the transaction like an envelope, and the parameters you send to the function call are the contents of the letter you put inside, then adding a `value` is like putting cash inside the envelope — the letter and the money get delivered together to the recipient.

{% hint style="warning" %}
If a function is not marked payable and you try to send Ether to it as above, the function will reject your transaction.
{% endhint %}

### Function Modifier Example

* <https://solidity-by-example.org/function-modifier>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

contract FunctionModifier {
    // We will use these variables to demonstrate how to use modifiers.
    address public owner;
    uint public x = 10;
    bool public locked;

    constructor() {
        // Set the transaction sender as the owner of the contract.
        owner = msg.sender;
    }

    // Modifier to check that the caller is the owner of the contract.
    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        // Underscore is a special character only used inside a function modifier
        // and it tells Solidity to execute the rest of the code.
        _;
    }

    // Modifiers can take inputs. This modifier checks that the
    // address passed in is not the zero address.
    modifier validAddress(address _addr) {
        require(_addr != address(0), "Not valid address");
        _;
    }

    function changeOwner(address _newOwner) public onlyOwner validAddress(_newOwner) {
        owner = _newOwner;
    }

    // Modifiers can be called before and / or after a function.
    // This modifier prevents a function from being called while it is still executing.
    modifier noReentrancy() {
        require(!locked, "No reentrancy");

        locked = true;
        _;
        locked = false;
    }

    function decrement(uint i) public noReentrancy {
        x -= i;
        if (i > 1) {
            decrement(i - 1);
        }
    }
}
```


# If / Else / For / While Loops

### If Statements

If statements in Solidity look just like javascript.

```solidity
function eatBLT(string memory sandwich) public {
  // Remember with strings, we have to compare their keccak256 hashes
  // to check equality
  if (keccak256(abi.encodePacked(sandwich)) == keccak256(abi.encodePacked("BLT"))) {
    eat();
  }
}
```

### Example - If / Else

* <https://solidity-by-example.org/if-else/>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

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) {
        // if (_x < 10) {
        //     return 1;
        // }
        // return 2;

        // shorthand way to write if / else statement
        // the "?" operator is called the ternary operator
        return _x < 10 ? 1 : 2;
    }
}
```

### For Loops

Sometimes you'll want to use a for loop to build the contents of an array in a function rather than simply saving that array to storage.

For our `getZombiesByOwner` function, a naive implementation would be to store a `mapping` of owners to zombie armies in the `ZombieFactory` contract:

```solidity
mapping (address => uint[]) public ownerToZombies
```

Then every time we create a new zombie, we would simply use `ownerToZombies[owner].push(zombieId)` to add it to that owner's zombies array. And `getZombiesByOwner` would be a very straightforward function:

```solidity
function getZombiesByOwner(address _owner) external view returns (uint[] memory) {
  return ownerToZombies[_owner];
}
```

#### The problem with this approach

This approach is tempting for its simplicity. But let's look at what happens if we later add a function to transfer a zombie from one owner to another.\
That transfer function would need to:

1. Push the zombie to the new owner's `ownerToZombies` array,
2. Remove the zombie from the old owner's `ownerToZombies` array,
3. Shift every zombie in the older owner's array up one place to fill the hole, and then
4. Reduce the array length by 1.

Step 3 would be extremely expensive gas-wise, since we'd have to do a write for every zombie whose position we shifted. If an owner has 20 zombies and trades away the first one, we would have to do 19 writes to maintain the order of the array.

Since writing to storage is one of the most expensive operations in Solidity, every call to this transfer function would be extremely expensive gas-wise. And worse, it would cost a different amount of gas each time it's called, depending on how many zombies the user has in their army and the index of the zombie being traded. So the user wouldn't know how much gas to send.hin

{% hint style="info" %}
Of course, we could just move the last zombie in the array to fill the missing slot and reduce the array length by one. But then we would change the ordering of our zombie army every time we made a trade.
{% endhint %}

Since view functions don't cost gas when called externally, we can simply use a for-loop in `getZombiesByOwner` to iterate the entire zombies array and build an array of the zombies that belong to this specific owner. Then our `transfer` function will be much cheaper, since we don't need to reorder any arrays in storage, and somewhat counter-intuitively this approach is cheaper overall.

### Using for loops

* The syntax of `for`loops in Solidity is similar to JavaScript.
* Solidity supports `for`, `while`, and `do while` loops.
* Don't write loops that are unbounded as this can hit the gas limit, causing your transaction to fail.
  * For the reason above, while and do while loops are rarely used.

\
Let's look at an example where we want to make an array of even numbers:

```solidity
function getEvens() pure external returns(uint[] memory) {
  uint[] memory evens = new uint[](5);
  // Keep track of the index in the new array:
  uint counter = 0;
  // Iterate 1 through 10 with a for loop:
  for (uint i = 1; i <= 10; i++) {
    // If `i` is even...
    if (i % 2 == 0) {
      // Add it to our array
      evens[counter] = i;
      // Increment counter to the next empty index in `evens`:
      counter++;
    }
  }
  return evens;
}
```

This function will return an array with the contents `[2, 4, 6, 8, 10]`.

### Example - For and While Loop

* <https://solidity-by-example.org/loop/>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

contract Loop {
    function loop() public {
        // for loop
        for (uint i = 0; i < 10; i++) {
            if (i == 3) {
                // Skip to next iteration with continue
                continue;
            }
            if (i == 5) {
                // Exit loop with break
                break;
            }
        }

        // while loop
        uint j;
        while (j < 10) {
            j++;
        }
    }
}
```


# Inheritance

* Rather than making one extremely long contract, sometimes it makes sense to split your code logic across multiple contracts to organize the code.
* One feature of Solidity that makes this more manageable is contract `inheritance`.
* Solidity supports multiple inheritance. 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`.
* Order of inheritance is important.
* You have to list the parent contracts in the order from “most base-like” to “most derived”.

```solidity
contract Doge {
  function catchphrase() public returns (string memory) {
    return "So Wow CryptoDoge";
  }
}

contract BabyDoge is Doge {
  function anotherCatchphrase() public returns (string memory) {
    return "Such Moon BabyDoge";
  }
}
```

`BabyDoge` inherits from `Doge`. That means if you compile and deploy `BabyDoge`, it will have access to both `catchphrase()`and `anotherCatchphrase()` (and any other public functions we may define on `Doge`).

This can be used for logical inheritance (such as with a subclass, a Cat is an Animal). But it can also be used simply for organizing your code by grouping similar logic together into different contracts.

### Example when constructor arguments are required

{% code fullWidth="true" %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import "./FundMe.sol";

contract FundMeMatching is FundMe {
    // Type declarations
    using PriceConverter for uint256; // Extends uint256 (used from msg.value) to enable direct price conversion

    /**
     * This is how to create a constructor for an inherited contract
     * if the parent already has a constructor that has arguments passed
     * https://docs.soliditylang.org/en/develop/contracts.html#arguments-for-base-constructors
     */
    constructor(address priceFeedAddress) FundMe(priceFeedAddress) {}

    function fund() public payable override {
        if (msg.value.getConversionRate(s_priceFeed) <= MINIMUM_USD)
            revert FundMe__NotEnoughEthSent();
        s_addressToAmountFunded[msg.sender] += msg.value;
        s_funders.push(msg.sender);
    }
}
```

{% endcode %}

### Example

* <https://solidity-by-example.org/inheritance/>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

/* 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();
    }
}
```

### Inherited State Variables

* Unlike functions, state variables cannot be overridden by re-declaring it in the child contract.
* The only way it can be overridden is by setting it directly in the construction of the child contract.
  * <https://solidity-by-example.org/shadowing-inherited-state-variables/>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

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"
}
```


# Interfaces

* Used to create the ABI of a referenced contract without having to actually include all the functions
  * So you say "This contract that I'm referencing has a `fund()` function"
  * This means it can be called, but you don't actually need to know what happens inside the function, you just need to know the name and inputs

{% hint style="info" %}
**CAN NOT:**

* have any functions implemented
* inherit from other contracts, but they can inherit from other interfaces
* declare a constructor
* declare state variables
* declare modifiers

**All declared functions must be external**
{% endhint %}

### Using an Interface

```solidity
interface NumberInterface {
  function getNum(address _myAddress) external view returns (uint);
}

contract MyContract {
  address NumberInterfaceAddress = 0xab38... 
  NumberInterface numberContract = NumberInterface(NumberInterfaceAddress);

  function someFunction() public {
    uint num = numberContract.getNum(msg.sender);
  }
}
```

In this way, your contract can interact with any other contract on the Ethereum blockchain, as long they expose those functions as `public` or `external`.

### Example

* <https://solidity-by-example.org/interface/>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

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);
    }
}
```


# Keccak256

* <https://medium.com/0xcode/hashing-functions-in-solidity-using-keccak256-70779ea55bb0>

Ethereum has the hash function `keccak256` built-in, which is a version of SHA3. A hash function basically maps an input into a random 256-bit hexadecimal number. A slight change in the input will cause a large change in the hash.

`keccak256` expects a single parameter of type bytes. This means that we have to "pack" any parameters before calling keccak256:

```solidity
//6e91ec6b618bb462a4a6ee5aa2cb0e9cf30f7a052bb467b0ba58b8748c00d2e5
keccak256(abi.encodePacked("aaaab"));

//b1f078126895a1424524de5321b339ab00408010b7cf0e6ed451514981e58aa9
keccak256(abi.encodePacked("aaaac"));
```

As you can see, the returned values are totally different despite only a 1-character change in the input.


# Library

* Can't have state variables.
* Can't send ETH.
* All functions must be internal.
* Library functions can be called directly if they do not modify the state.
  * That means pure or view functions only can be called from outside the library.
* Library can not be destroyed as it is assumed to be stateless.
* A Library cannot inherit any element.
* A Library cannot be inherited.


# Mappings

* A mapping is essentially a key-value store for storing and looking up data
* Mappings can't be in memory

```solidity
mapping(keyType => valueType)
```

* Here the key is an `address` and the value is a `uint256`
  * E.g. for a financial app, storing a uint that holds the user's account balance:

```solidity
mapping (address => uint) public addressToAccountBalance;
```

* Here the key is a uint and the value a string
  * e.g. Store / lookup usernames based on userId

```solidity
mapping (uint => string) userIdToName;
```

### Example

* <https://solidity-by-example.org/mapping/>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

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 (0).
        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];
    }
}
```

### Example - Nested Mapping

* <https://solidity-by-example.org/mapping/>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

contract NestedMapping {
    // Nested mapping (mapping from address to another mapping)
    mapping(address => mapping(uint => bool)) public nested;

    function get(address _addr1, uint _i) public view returns (bool) {
        // You can get values from a nested mapping
        // even when it is not initialized
        return nested[_addr1][_i];
    }

    function set(
        address _addr1,
        uint _i,
        bool _boo
    ) public {
        nested[_addr1][_i] = _boo;
    }

    function remove(address _addr1, uint _i) public {
        delete nested[_addr1][_i];
    }
}
```


# msg.sender

In Solidity, there are certain global variables that are available to all functions. One of these is `msg.sender`, which refers to the `address`of the person (or smart contract) who called the current function.

{% hint style="info" %}
In Solidity, function execution always needs to start with an external caller. A contract will just sit on the blockchain doing nothing until someone calls one of its functions. So there will always be a `msg.sender`.
{% endhint %}

Here's an example of using `msg.sender` and updating a `mapping`:

```solidity
mapping (address => uint) favoriteNumber;

function setMyNumber(uint _myNumber) public {
  // Update our `favoriteNumber` mapping to store `_myNumber` under `msg.sender`
  favoriteNumber[msg.sender] = _myNumber;
  // ^ The syntax for storing data in a mapping is just like with arrays
}

function whatIsMyNumber() public view returns (uint) {
  // Retrieve the value stored in the sender's address
  // Will be `0` if the sender hasn't called `setMyNumber` yet
  return favoriteNumber[msg.sender];
}
```

In this trivial example, anyone could call `setMyNumber`and store a `uint`in our contract, which would be tied to their address. Then when they called `whatIsMyNumber`, they would be returned the uint that they stored.

Using `msg.sender` gives you the security of the Ethereum blockchain — the only way someone can modify someone else's data would be to steal the private key associated with their Ethereum address.


# Objects & Types

### Types of Objects

* <https://docs.soliditylang.org/en/v0.8.13/types.html>

<table data-full-width="true"><thead><tr><th width="388">Type</th><th>Description</th></tr></thead><tbody><tr><td><pre class="language-solidity"><code class="lang-solidity">uint
uint8
uint16
uint32
uint64
uint256
</code></pre></td><td><ul><li>Unsigned integer (whole number)</li><li><p>256 is the default if nothing is specified</p><ul><li>But it's good to be specific and use <code>uint256</code></li></ul></li><li>Initializes as default <code>0</code> if not assigned a value as that is the null value in Solidity</li><li>Smallest is <code>unit8</code> as 8 bits is a byte</li></ul></td></tr><tr><td><pre class="language-solidity"><code class="lang-solidity">int
</code></pre></td><td><ul><li>Positive or negative whole number</li></ul></td></tr><tr><td><pre class="language-solidity"><code class="lang-solidity">bytes
bytes2
bytes3
bytes5
bytes22
bytes32
</code></pre></td><td><ul><li><code>bytes32</code> is the max size allowed</li><li><p><code>bytes</code> can have "any size"?</p><ul><li>But I think that will still limit the actual content to 32 bytes</li></ul></li></ul></td></tr><tr><td><pre class="language-solidity"><code class="lang-solidity">string
</code></pre></td><td><ul><li>Actually a type of <code>bytes</code> in the background, but only used for text</li></ul></td></tr><tr><td><pre class="language-solidity"><code class="lang-solidity">bool
</code></pre></td><td><ul><li>boolean</li><li>true/false</li></ul></td></tr><tr><td><pre class="language-solidity"><code class="lang-solidity">address
</code></pre></td><td><ul><li>An address!</li></ul></td></tr></tbody></table>

```solidity
contract SimpleStorage {
    bool hasFavouriteNumber = true;
    uint256 favouriteNumber = 5;
    string favouriteNumberInText = "Five";
    int256 favouriteInt = -5;
    address myAddress = 0x5E666460E5BB4A8Bb14E805478176c36f3b293AB;
    bytes32 favouriteBytes = "cat";
}
```

### Example

* <https://solidity-by-example.org/primitives/>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

contract Primitives {
    bool public boo = true;

    /*
    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
    */
    uint8 public u8 = 1;
    uint public u256 = 456;
    uint public u = 123; // uint is an alias for uint256

    /*
    Negative numbers are allowed for int types.
    Like uint, different ranges are available from int8 to int256
    
    int256 ranges from -2 ** 255 to 2 ** 255 - 1
    int128 ranges from -2 ** 127 to 2 ** 127 - 1
    */
    int8 public i8 = -1;
    int public i256 = 456;
    int public i = -123; // int is same as int256

    // minimum and maximum of int
    int public minInt = type(int).min;
    int public maxInt = type(int).max;

    address public addr = 0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c;

    /*
    In Solidity, the data type byte represent a sequence of bytes. 
    Solidity presents two type of bytes types :

     - fixed-sized byte arrays
     - dynamically-sized byte arrays.
     
     The term bytes in Solidity represents a dynamic array of bytes. 
     It’s a shorthand for byte[] .
    */
    bytes1 a = 0xb5; //  [10110101]
    bytes1 b = 0x56; //  [01010110]

    // Default values
    // Unassigned variables have a default value
    bool public defaultBoo; // false
    uint public defaultUint; // 0
    int public defaultInt; // 0
    address public defaultAddr; // 0x0000000000000000000000000000000000000000
}
```


# OpenZeppelin

```solidity
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";

import {Base64} from "@openzeppelin/contracts/utils/Base64.sol";
```


# Payable

### Payable

* Functions and addresses declared `payable` can receive `ether` into the contract
* <https://solidity-by-example.org/payable/>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

contract Payable {
    // Payable address can receive Ether
    address payable public owner;

    // Payable constructor can receive Ether
    constructor() payable {
        owner = payable(msg.sender);
    }

    // Function to deposit Ether into this contract.
    // Call this function along with some Ether.
    // The balance of this contract will be automatically updated.
    function deposit() public payable {}

    // Call this function along with some Ether.
    // The function will throw an error since this function is not payable.
    function notPayable() public {}

    // Function to withdraw all Ether from this contract.
    function withdraw() public {
        // get the amount of Ether stored in this contract
        uint amount = address(this).balance;

        // send all Ether to owner
        // Owner can receive Ether since the address of owner is payable
        (bool success, ) = owner.call{value: amount}("");
        require(success, "Failed to send Ether");
    }

    // Function to transfer Ether from this contract to address from input
    function transfer(address payable _to, uint _amount) public {
        // Note that "to" is declared as payable
        (bool success, ) = _to.call{value: _amount}("");
        require(success, "Failed to send Ether");
    }
}
```


# Public State Variable vs Function

### **Using a Function**

```solidity
solidityCopy codefunction name() public pure returns (string memory) {
    return "Manual Token";
}
```

This is a function that, when called, returns the string "Manual Token". Each time this function is called, it consumes gas because it's a transaction on the Ethereum network. However, since it's a `pure` function (not reading from or modifying the state), the gas cost is relatively low. But it's important to note that every call to this function is a read operation on the blockchain.

### **Using a Public State Variable**

```solidity
solidityCopy codestring public name = "Manual Token";
```

This approach declares `name` as a public state variable. In Solidity, public state variables automatically have a getter function created by the compiler. This means that when `name` is accessed, it's done through an auto-generated function that's similar to the manually written function in the first approach.

The key difference is that reading this public state variable is a read-only operation and does not consume gas if called externally (i.e., outside of a transaction). However, the initial deployment of the contract will cost slightly more gas because this variable is stored on the blockchain as part of the contract's state.

In terms of gas efficiency for reads:

* If you're only concerned about the cost of reading the value (and not the deployment cost), using the public state variable (`string public name = "Manual Token";`) is more gas-efficient since it doesn't cost gas to read from a public state variable.
* If considering the cost of contract deployment, the function approach might use slightly less gas at deployment time, but this is a one-time cost.

In summary, for most practical purposes, especially if the `name` will be read frequently, using the public state variable is the more gas-efficient approach due to free external reads.


# Receive & Fallback

```solidity
/**
* Explainer from: https://solidity-by-example.org/fallback
* ETH is sent to contract
*      is msg.data empty?
*           /    \
*         yes    no
*         /       \
*    receive()?  fallback()
*      /     \
*    yes     no
*    /        \
* receive()  fallback()
*/
```

## Fallback

* `fallback` is a function that does not take any arguments and does not return anything.
* It is executed either when:
  * A function that does not exist is called
  * Ether is sent directly to a contract but `receive()` does not exist or `msg.data` is not empty
* `fallback` has a 2300 gas limit when called by `transfer` or `send`

### Fallback Example

* <https://solidity-by-example.org/fallback/>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Fallback {
    event Log(uint gas);

    // Fallback function must be declared as external.
    fallback() external payable {
        // send / transfer (forwards 2300 gas to this fallback function)
        // call (forwards all of the gas)
        emit Log(gasleft());
    }

    // Helper function to check the balance of this contract
    function getBalance() public view returns (uint) {
        return address(this).balance;
    }
}

contract SendToFallback {
    function transferToFallback(address payable _to) public payable {
        _to.transfer(msg.value);
    }

    function callFallback(address payable _to) public payable {
        (bool sent, ) = _to.call{value: msg.value}("");
        require(sent, "Failed to send Ether");
    }
}
```

## Receive

The `receive` function in Solidity is a special type of function that is triggered when ETH is sent to a contract and `msg.data` is empty. It's a newer addition to Solidity, designed to make contracts more intuitive and safer. This function is executed in the following scenarios:

When ETH is sent to the contract with an empty `msg.data`.

* If `receive()` exists, and `msg.data` is empty, this function is invoked.
* If `receive()` does not exist, but Ether is sent with empty `msg.data`, the `fallback` function is used instead.

This function is specified with the `receive() external payable` declaration, indicating that it can receive ETH. The use of `receive()` makes the intentions of a contract regarding Ether transfers more explicit, which is crucial for contract security and functionality.

### Receive Example

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract ReceiveExample {
    event Received(address sender, uint amount);

    // The receive function is triggered when Ether is sent to the contract.
    receive() external payable {
        emit Received(msg.sender, msg.value);
    }

    // Helper function to check the balance of this contract
    function getBalance() public view returns (uint) {
        return address(this).balance;
    }
}

```

In this example, when Ether is sent to the `ReceiveExample` contract with empty `msg.data`, the `receive()` function is triggered, and it emits an event logging the sender's address and the amount of Ether sent. The `getBalance` function is a helper that allows querying the contract's balance.


# Security

* <https://docs.openzeppelin.com/contracts/4.x/api/security>
  * These contracts aim to cover common security practices

### PullPayment

* A pattern that can be used to avoid reentrancy attacks

### ReentrancyGuard

* <https://solidity-by-example.org/hacks/re-entrancy/>
* A modifier that can prevent reentrancy during certain functions

```solidity
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract FundMe is ReentrancyGuard {
...

    function withdraw() external payable onlyOwner nonReentrant {
...
```

### Pausable

* A common emergency response mechanism that can pause functionality while a remediation is pending

### Constructor

* Older versions of Solidity didn't have the `constructor` keyword
* It took the function with *EXACTLY*  the same name as the contract and used that as the constructor
* So... if you got the name wrong even a little bit, the constructor wouldn't run and become accessible to anyone
* Rubixi bug: <https://www.youtube.com/watch?v=h4dxwYQQ_b8>

### Self Destruct

* <https://solidity-by-example.org/hacks/self-destruct/>
* If you send funds then immediately call `selfdestruct()` then the contract you call could try to revert and send the funds back, but it can't since you selfdestructed, so it keeps the funds, but doesn't continue with the code past the revert point
* If you code your contract badly, this could brick the function (e.g. setting a winner after checking the current balance)
* Therefore, use a counter that is part of the function, instead of `address(this).balance` so that the code is executed as expected during revert

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

// The goal of this game is to be the 7th player to deposit 1 Ether.
// Players can deposit only 1 Ether at a time.
// Winner will be able to withdraw all Ether.

/*
1. Deploy EtherGame
2. Players (say Alice and Bob) decides to play, deposits 1 Ether each.
2. Deploy Attack with address of EtherGame
3. Call Attack.attack sending 5 ether. This will break the game
   No one can become the winner.

What happened?
Attack forced the balance of EtherGame to equal 7 ether.
Now no one can deposit and the winner cannot be set.
*/

contract EtherGame {
    uint256 public targetAmount = 7 ether;
    address public winner;

    function deposit() public payable {
        require(msg.value == 1 ether, "You can only send 1 Ether");

        uint balance = address(this).balance;
        require(balance <= targetAmount, "Game is over");

        // ********************
        // THIS IS THE PROBLEM
        // Winner is set after the check, but the check fails and reverts, so the winner is never set
        // even though the value of address(this).balance is now greater than 7
        // ********************    
        if (balance == targetAmount) {
            winner = msg.sender;
        }
    }

    function claimReward() public {
        require(msg.sender == winner, "Not winner");

        (bool sent, ) = msg.sender.call{value: address(this).balance}("");
        require(sent, "Failed to send Ether");
    }
}

contract Attack {
    EtherGame etherGame;

    constructor(EtherGame _etherGame) {
        etherGame = EtherGame(_etherGame);
    }

    function attack() public payable {
        // You can simply break the game by sending ether so that
        // the game balance >= 7 ether

        // cast address to payable
        address payable addr = payable(address(etherGame));
        selfdestruct(addr);
    }
}
```

* So instead, use a global balance variable to keep track of the funds, not just the contract balance

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

contract EtherGame {
    uint256 public targetAmount = 3 ether;
    uint256 public balance;
    address public winner;

    function deposit() public payable {
        require(msg.value == 1 ether, "You can only send 1 Ether");

        balance += msg.value;
        require(balance <= targetAmount, "Game is over");

        if (balance == targetAmount) {
            winner = msg.sender;
        }
    }

    function claimReward() public {
        require(msg.sender == winner, "Not winner");

        (bool sent, ) = msg.sender.call{value: balance}("");
        require(sent, "Failed to send Ether");
    }
}
```


# Self Destruct

### EIP-6780: SELFDESTRUCT only in same transaction

{% embed url="<https://eips.ethereum.org/EIPS/eip-6780>" %}

### Example

* [https://solidity-by-example.org/hacks/self-destruct](https://solidity-by-example.org/hacks/self-destruct/)


# Send ETH (transfer, send, call)

### How to send Ether

You can send Ether to other contracts by

* `transfer` (2300 gas, throws error)
* `send` (2300 gas, returns bool)
* `call` (forward all gas or set gas, returns bool)

### How to receive Ether

A contract receiving Ether must have at least one of the functions below

* `receive()` external payable
* `fallback()` external payable
* `receive()` is called if `msg.data` is empty, otherwise `fallback()` is called.

### Which method should you use?

* `call` in combination with re-entrancy guard is the recommended method to use after December 2019.

### Guard against re-entrancy

* Making all state changes before calling other contracts.
* Using re-entrancy guard modifier.

### Example

* <https://solidity-by-example.org/sending-ether/>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

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");
    }
}
```

### Example - Call

* `call` is a low level function to interact with other contracts
* This is the recommended method to use when you're just sending Ether via calling the `fallback` function
* However it is not the recommend way to call existing functions
* <https://solidity-by-example.org/call/>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

contract Receiver {
    event Received(address caller, uint amount, string message);

    fallback() external payable {
        emit Received(msg.sender, msg.value, "Fallback was called");
    }

    function foo(string memory _message, uint _x) public payable returns (uint) {
        emit Received(msg.sender, msg.value, _message);

        return _x + 1;
    }
}

contract Caller {
    event Response(bool success, bytes data);

    // Let's imagine that contract B does not have the source code for
    // contract A, but we do know the address of A and the function to call.
    function testCallFoo(address payable _addr) public payable {
        // You can send ether and specify a custom gas amount
        (bool success, bytes memory data) = _addr.call{value: msg.value, gas: 5000}(
            abi.encodeWithSignature("foo(string,uint256)", "call foo", 123)
        );

        emit Response(success, data);
    }

    // Calling a function that does not exist triggers the fallback function.
    function testCallDoesNotExist(address _addr) public {
        (bool success, bytes memory data) = _addr.call(
            abi.encodeWithSignature("doesNotExist()")
        );

        emit Response(success, data);
    }
}
```

### Call - Specify Function

* <https://kushgoyal.com/ethereum-solidity-how-use-call-delegatecall/>

{% code fullWidth="true" %}

```solidity
function myFunction(uint _x, address _addr) public returns(uint, uint) {
    // do something
    return (a, b);
}

// function signature string should not have any spaces
// 10 is the first parameter _x
// msg.sender is the second parameter _addr
(bool success, bytes memory result) = addr.call(abi.encodeWithSignature("myFunction(uint,address)", 10, msg.sender));
```

{% endcode %}

### Delegatecall

* `delegatecall` is a low level function similar to `call`
* `delegatecall` syntax is exactly the same as `call` syntax except it cannot accept the `value` option but only `gas`
* When contract A executes `delegatecall` to contract B, B's code is executed
* with contract A's storage, `msg.sender` and `msg.value`
* A popular and very useful use case for `delegatecall` is upgradable contracts
  * Upgradable contracts use a proxy contract which forwards all the function calls to the implementation contract using `delegatecall`
  * The address of the proxy contract remains constant while new implementations can be deployed multiple times
  * The address of the new implementation gets updated in the proxy contract

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

// NOTE: 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)
        );
    }
}
```


# Stack Too Deep

In Solidity, the "stack too deep" error occurs when you have too many local variables in a function. This is a limitation of the Ethereum Virtual Machine (EVM), which Solidity compiles down to. The EVM has a limit on the number of local variables a function can handle, which is typically around 16. This includes explicit local variables, function arguments, and return parameters.

The reason for this limitation is the EVM's design, which uses a stack-based architecture. Each operation in the EVM (including function calls) has a stack to store its data, and this stack has a limited size.

To avoid the "stack too deep" error, you can:

1. **Reduce the number of local variables**: Try to minimize the number of variables in your function. Combine related variables into structs if possible.
2. **Optimize your code**: Sometimes, rearranging the order of variables or breaking a function into smaller functions can help.
3. **Use State Variables**: If some variables can be moved to the contract's state level (outside of the function), this can reduce the number of local variables.
4. **Use Memory Arrays**: For temporary storage of a collection of items, consider using memory arrays.
5. **Inline Functions**: If you're using small helper functions within a larger function, consider inlining these if they are not reused elsewhere.

Be aware that these workarounds might affect gas costs and contract readability, so they should be used judiciously.

<figure><img src="/files/NziFAx4Szm970NM1KXg0" alt=""><figcaption><p><a href="https://twitter.com/PaulRBerg/status/1612043506545033218">https://twitter.com/PaulRBerg/status/1612043506545033218</a></p></figcaption></figure>


# Structs

* Structs can be declared outside of a contract and imported in another contract.
* Sometimes you need a more complex data type.
* For this, Solidity provides structs, allowing you to create more complicated data types that have multiple properties.

```solidity
struct People {
  uint256 favoriteNumber;
  string name;
}

// create a New Person:
People public person = People({favoriteNumber: 7, name: "Eridian"});
```

### Declaring and Importing Struct

{% code title="File that the struct is declared in" %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
// This is saved as 'StructDeclaration.sol'

struct Todo {
    string text;
    bool completed;
}
```

{% endcode %}

{% code title="File that imports the struct above" %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import "./StructDeclaration.sol";

contract Todos {
    // An array of 'Todo' structs
    Todo[] public todos;
}
```

{% endcode %}

### Passing structs as arguments

* You can pass a storage pointer to a struct as an argument to a `private` or `internal` function.
* This is useful, for example, for passing around our `Zombie` structs between functions.

```solidity
function _doStuff(People storage _person) internal {
  // do stuff with _person
}
```

* This way we can pass a reference to our person into a function instead of passing in a person ID and looking it up.

### Struct packing to save gas

* There are other types of `uint`s: `uint8`, `uint16`, `uint32`, etc.
* Normally there's no benefit to using these sub-types because Solidity reserves 256 bits of storage regardless of the `uint` size.&#x20;
  * For example, using `uint8` instead of `uint (uint256)` won't save you any gas.
* But there's an exception to this: inside `struct`s.
* If you have multiple `uint`s inside a struct, using a smaller-sized `uint`when possible will allow Solidity to pack these variables together to take up less storage.&#x20;

```solidity
struct NormalStruct {
  uint a;
  uint b;
  uint c;
}

struct MiniMe {
  uint32 a;
  uint32 b;
  uint c;
}

// `mini` will cost less gas than `normal` because of struct packing
NormalStruct normal = NormalStruct(10, 20, 30);
MiniMe mini = MiniMe(10, 20, 30);
```

* For this reason, inside a struct you'll want to use the smallest integer sub-types you can get away with.
* You'll also want to cluster identical data types together (i.e. put them next to each other in the struct) so that Solidity can minimize the required storage space.
* For example, a struct with fields `uint c; uint32 a; uint32 b;` will cost less gas than a struct with fields `uint32 a; uint c; uint32 b;` because the `uint32` fields are clustered together.

### Example

* <https://solidity-by-example.org/structs/>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

contract Todos {
    struct Todo {
        string text;
        bool completed;
    }

    // An array of 'Todo' structs
    Todo[] public todos;

    function create(string calldata _text) public {
        // 3 ways to initialize a struct
        // - calling it like a function
        todos.push(Todo(_text, false));

        // key value mapping
        todos.push(Todo({text: _text, completed: false}));

        // initialize an empty struct and then update it
        Todo memory todo;
        todo.text = _text;
        // todo.completed initialized to false

        todos.push(todo);
    }

    // Solidity automatically created a getter for 'todos' so you don't actually need this function.
    function get(uint _index) public view returns (string memory text, bool completed) {
        Todo storage todo = todos[_index];
        return (todo.text, todo.completed);
    }

    // update text
    function updateText(uint _index, string calldata _text) public {
        Todo storage todo = todos[_index];
        todo.text = _text;
    }

    // update completed
    function toggleCompleted(uint _index) public {
        Todo storage todo = todos[_index];
        todo.completed = !todo.completed;
    }
}
```


# Style Guide

### Soliditylang Style Guide:

{% embed url="<https://docs.soliditylang.org/en/latest/style-guide.html>" %}

### Chainlink Style Guide:

* <https://github.com/smartcontractkit/chainlink/blob/develop/contracts/STYLE_GUIDE.md>


# Time Units

Solidity provides some native units for dealing with time.

The variable `now`will return the current unix timestamp of the latest block (the number of seconds that have passed since January 1st 1970). The unix time as I write this is `1515527488`.

{% hint style="info" %}
Unix time is traditionally stored in a 32-bit number. This will lead to the "Year 2038" problem, when 32-bit unix timestamps will overflow and break a lot of legacy systems.

So if we wanted our DApp to keep running 20 years from now, we could use a 64-bit number instead — but our users would have to spend more gas to use our DApp in the meantime. Design decisions!
{% endhint %}

Solidity also contains the time units

* `seconds`
* `minutes`
* `hours`
* `days`
* `weeks`
* `years`

These will convert to a uint of the number of seconds in that length of time.

Here's an example of how these time units can be useful:

```solidity
uint lastUpdated;

// Set `lastUpdated` to `now`
function updateTimestamp() public {
  lastUpdated = now;
}

// Will return `true` if 5 minutes have passed since `updateTimestamp` was 
// called, `false` if 5 minutes have not passed
function fiveMinutesHavePassed() public view returns (bool) {
  return (now >= (lastUpdated + 5 minutes));
}
```

```solidity
uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime))) - 1;
```

{% hint style="info" %}
The `uint32(...)` is necessary because `now`returns a `uint256`by default. So we need to explicitly convert it to a `uint32`.
{% endhint %}


# Try / Catch

{% hint style="info" %}
Great article explaining how Solidity reverts, custom errors, and try/catch work:

<https://www.rareskills.io/post/try-catch-solidity>
{% endhint %}


# Typecasting

Sometimes you need to convert between data types.

```solidity
uint8 a = 5;
uint b = 6;
// throws an error because a * b returns a uint, not uint8:
uint8 c = a * b;
// we have to typecast b as a uint8 to make it work:
uint8 c = a * uint8(b);
```

In the above, `a * b` returns a `uint`, but we were trying to store it as a `uint8`, which could cause potential problems. By casting it as a `uint8`, it works and the compiler won't throw an error.


# Using Directive

{% embed url="<https://docs.soliditylang.org/en/v0.8.26/grammar.html#a4.SolidityParser.usingDirective>" %}

{% hint style="warning" %}
Not inherited by child contracts. It must be imported and defined in every contract in which the "Using Directive" is used.
{% endhint %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {Address} from "@openzeppelin/contracts/utils/Address.sol";

contract UsingDirective {
    using Address for address payable;

    function sendETH(address _to) public payable {
        payable(address(_to)).sendValue(msg.value);
    }
}
```


# Variables, Consts & Immutable

### Variables

There are 3 types of variables in Solidity:

* `local`
  * Declared inside a function.
  * Not stored on the blockchain.
* `state`
  * Declared outside a function.
  * Stored on the blockchain.
* `global`
  * Provides information about the blockchain.

### Example - Variables

* <https://solidity-by-example.org/variables/>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

contract Variables {
    // State variables are stored on the blockchain.
    string public text = "Hello";
    uint public num = 123;

    function doSomething() public {
        // Local variables are not saved to the blockchain.
        uint i = 456;

        // Here are some global variables
        uint timestamp = block.timestamp; // Current block timestamp
        address sender = msg.sender; // address of the caller
    }
}
```

### Constants

* Constants are variables that cannot be modified
* Their value is hard coded into the bytecode of the contract
* Using constants can save gas cost

### Example - Constants

* <https://solidity-by-example.org/constants/>

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

contract Constants {
    // coding convention to uppercase constant variables
    address public constant MY_ADDRESS = 0x777788889999AaAAbBbbCcccddDdeeeEfFFfCcCc;
    uint public constant MY_UINT = 123;
}
```

### Immutable

* Immutable variables are like constants
* Values of immutable variables can be set inside the `constructor` but cannot be modified afterwards

### Example - Immutable

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

contract Immutable {
    // coding convention to uppercase constant variables
    address public immutable MY_ADDRESS;
    uint public immutable MY_UINT;

    constructor(uint _myUint) {
        MY_ADDRESS = msg.sender;
        MY_UINT = _myUint;
    }
}
```


# Withdraws

After you send Ether to a contract, it gets stored in the contract's Ethereum account, and it will be trapped there — unless you add a function to withdraw the Ether from the contract.

You can write a function to withdraw Ether from the contract as follows:

```solidity
contract GetPaid is Ownable {
  function withdraw() external onlyOwner {
    address payable _owner = address(uint160(owner()));
    _owner.transfer(address(this).balance);
  }
}
```

Note that we're using `owner()` and `onlyOwner` from the `Ownable` contract, assuming that was imported.

It is important to note that you cannot transfer Ether to an address unless that address is of type `address payable`. But the `_owner` variable is of type `uint160`, meaning that we must explicitly cast it to `address payable`.

Once you cast the address from `uint160` to `address payable`, you can transfer Ether to that address using the `transfer` function, and `address(this).balance` will return the total balance stored on the contract. So if 100 users had paid 1 Ether to our contract, `address(this).balance` would equal 100 Ether.

You can use `transfer` to send funds to any Ethereum address. For example, you could have a function that transfers Ether back to the `msg.sender` if they overpaid for an item:

```solidity
uint itemFee = 0.001 ether;
msg.sender.transfer(msg.value - itemFee);
```

Or in a contract with a buyer and a seller, you could save the seller's address in storage, then when someone purchases his item, transfer him the fee paid by the buyer: `seller.transfer(msg.value)`.


# Foundry Notes

{% hint style="info" %}
**What is Foundry good for?**

* Deploying contracts and interacting with those contracts
* Running tests where everything is simulated

**What's it bad at?**

* Listening for events on a live blockchain
* Loops and timing scripts
  {% endhint %}

### Installation

* <https://getfoundry.sh/>

{% code title="Install Foundry" %}

```bash
curl -L https://foundry.paradigm.xyz | bash
```

{% endcode %}

### Initialize New Project

```bash
forge init <PROJECT_NAME>
```

### Install Dependencies

* The command `forge install` is used to install dependencies, such as libraries or other smart contracts that a project may need.

```bash
forge install OpenZeppelin/openzeppelin-contracts@v4.9.3 --no-commit
```

* By default, when you install a dependency using `forge install`, Foundry will automatically create a new Git commit that includes the changes to your project (such as modifications to the `foundry.toml` file and the addition of the OpenZeppelin contract files in your project directory).
* The `--no-commit` flag modifies this behavior. When you use this flag, Foundry will still install the OpenZeppelin contracts, but it will not automatically create a new Git commit for these changes. This means you have to manually commit the changes to your Git repository if you wish to do so.
* The use of `--no-commit` gives you more control over your Git history and commit messages, which can be useful in certain workflows or for maintaining a clean project history.

### Foundry Template Files

{% embed url="<https://github.com/EridianAlpha/foundry-template/tree/main>" %}

### Upgrade Foundry

* `foundryup` updates foundry, but for some reason the command might not be available on the command line, so run the installation script again, then call it.

```bash
curl -L https://foundry.paradigm.xyz | bash
foundryup
```


# Docs & GitHub Pages

Foundry has a built-in documentation feature that generates an `mdbook` for all contracts in the `src` directory. NATSPEC comments are used to populate the content. This can then be built using GitHub Actions and hosted using GitHub pages.

The default configuration is ok, but I've customized it with a GitHub action which on every push to the repo:

1. Builds the updated docs.
2. Customizes the config.
3. Commits the changes to the documentation branch `gh-pages`.
4. Publishes the updated docs on GitHub pages.

## Viewing Locally

To view the site locally run:

```bash
forge doc --build --serve --port=4000
```

* This won't have the config customizations made using the GitHub Actions workflow, but it can be useful for local development.

## GitHub Actions Workflow

* Create a workflow `.yml` file at `.github/workflows/deployGitHubPages.yml`

{% hint style="info" %}
Modify:

* \<ADD\_TITLE\_HERE>
* \<ADD\_AUTHOR\_HERE>
  {% endhint %}

{% code title=".github/workflows/deployGitHubPages.yml" fullWidth="true" %}

```yaml
name: Deploy Docs to GitHub Pages

on: [push]

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      contents: write

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Install Foundry
        uses: foundry-rs/foundry-toolchain@v1

      - name: Install Dependencies
        run: forge install

      - name: Generate Documentation
        run: forge doc

      - name: Edit book.toml
        run: |
          sed -i 's/title = ""/title = "<ADD_TITLE_HERE>"/' ./docs/book.toml                          # Set the title of the book
          sed -i 's/authors = \[\]/authors = \["<ADD_AUTHOR_HERE>"\]/' ./docs/book.toml               # Set the author of the book
          sed -i '/\[book\]/a language = "en"' ./docs/book.toml                                       # Add language setting under [book]
          sed -i '/\[book\]/a multilingual = false' ./docs/book.toml                                  # Add multilingual setting under [book]
          sed -i 's/no-section-label = true/no-section-label = false/' ./docs/book.toml               # Change no-section-label to false
          sed -i '/\[output.html\]/a default-theme = "dark"' ./docs/book.toml                         # Add default-theme under [output.html]
          sed -i '/\[output.html\]/a preferred-dark-theme = "ayu"' ./docs/book.toml                   # Add preferred-dark-theme under [output.html]
          sed -i '/^\[output.html.fold\]$/,/^\[/ s/^enable = true/enable = false/' ./docs/book.toml   # Change enable under [output.html.fold]

      - name: Edit SUMMARY.md
        run: |
          sed -i 's/❱ //g' ./docs/src/SUMMARY.md                                        # Removes the "❱ " from lines
          sed -i '/^# src$/d' ./docs/src/SUMMARY.md                                     # Deletes the line containing exactly "# src"
          sed -i 's/- \[Home\](README.md)/[README](README.md)/' ./docs/src/SUMMARY.md   # Replaces "- [Home](README.md)" with "[README](README.md)"

      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Install mdbook
        run: |
          mkdir mdbook
          curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.36/mdbook-v0.4.36-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook
          echo `pwd`/mdbook >> $GITHUB_PATH

      - name: Build book
        run: |
          cd ./docs
          mdbook build

      - name: Deploy to GitHub Pages
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./docs/book
```

{% endcode %}

### GitHub Pages Repo Settings

{% hint style="warning" %}
The branch `gh-pages` is created by the Actions workflow, so this step can only be completed after the Action has run successfully for the first time.
{% endhint %}

<div data-full-width="true"><figure><img src="/files/uvOropv98jdReRDaWzQW" alt=""><figcaption></figcaption></figure></div>


# Useful Commands

{% content-ref url="/pages/SwvXmoLJ5vgVczUgB7NI" %}
[Anvil](/ethereum-dev/foundry-notes/useful-commands/anvil)
{% endcontent-ref %}

{% content-ref url="/pages/dY5cPTInuXCuceu8Mmn7" %}
[Cast](/ethereum-dev/foundry-notes/useful-commands/cast)
{% endcontent-ref %}

{% content-ref url="/pages/qfn0VZZBFvZ59rh2nYbv" %}
[Forge](/ethereum-dev/foundry-notes/useful-commands/forge)
{% endcontent-ref %}

### Run Scripts

```
forge build
forge script script/<SCRIPT>:<CONTRACT_NAME> --rpc-url http://<RPC_URL>
forge script script/<SCRIPT>:<CONTRACT_NAME> --fork-url http://<RPC_URL>
```

* Foundry DevOps
  * A repo to get the most recent deployment from a given environment in Foundry. This way, you can do scripting off previous deployments in solidity.
  * <https://github.com/Cyfrin/foundry-devops>

```bash
forge install Cyfrin/foundry-devops --no-commit
```

```solidity
import {DevOpsTools} from "lib/foundry-devops/src/DevOpsTools.sol";
import {MyContract} from "my-contract/MyContract.sol";

function interactWithPreviouslyDeployedContracts() public {
    address contractAddress = DevOpsTools.get_most_recent_deployment("MyContract", block.chainid);
    MyContract myContract = MyContract(contractAddress);
    myContract.doSomething();
}
```

### Makefile

* `@` stops the command being printed out to the command line which is useful when you don't want sensitive info to be printed e.g. private keys.

{% tabs %}
{% tab title="FundMe Usage" %}
{% code overflow="wrap" %}

```makefile
-include .env

build:; forge build # ; is used to run multiple commands in one line

deploy-holesky:
	forge script script/DeployFundMe.s.sol:DeployFundMe --rpc-url $(HOLESKY_RPC_URL) --private-key $(HOLESKY_PRIVATE_KEY) --broadcast -vvvv

deploy-holesky-verify:
	forge script script/DeployFundMe.s.sol:DeployFundMe --rpc-url $(HOLESKY_RPC_URL) --private-key $(HOLESKY_PRIVATE_KEY) --broadcast --verify --etherscan-api-key $(ETHERSCAN_API_KEY) -vvvv
```

{% endcode %}
{% endtab %}

{% tab title="Full example" %}

```makefile
-include .env

.PHONY: all test clean deploy fund help install snapshot format anvil 

DEFAULT_ANVIL_KEY := 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80

help:
	@echo "Usage:"
	@echo "  make deploy [ARGS=...]\n    example: make deploy ARGS=\"--network sepolia\""
	@echo ""
	@echo "  make fund [ARGS=...]\n    example: make deploy ARGS=\"--network sepolia\""

all: clean remove install update build

# Clean the repo
clean  :; forge clean

# Remove modules
remove :; rm -rf .gitmodules && rm -rf .git/modules/* && rm -rf lib && touch .gitmodules && git add . && git commit -m "modules"

install :; forge install cyfrin/foundry-devops@0.0.11 --no-commit && forge install smartcontractkit/chainlink-brownie-contracts@0.6.1 --no-commit && forge install foundry-rs/forge-std@v1.5.3 --no-commit

# Update Dependencies
update:; forge update

build:; forge build

test :; forge test 

snapshot :; forge snapshot

format :; forge fmt

anvil :; anvil -m 'test test test test test test test test test test test junk' --steps-tracing --block-time 1

NETWORK_ARGS := --rpc-url http://localhost:8545 --private-key $(DEFAULT_ANVIL_KEY) --broadcast

ifeq ($(findstring --network sepolia,$(ARGS)),--network sepolia)
	NETWORK_ARGS := --rpc-url $(SEPOLIA_RPC_URL) --private-key $(PRIVATE_KEY) --broadcast --verify --etherscan-api-key $(ETHERSCAN_API_KEY) -vvvv
endif

deploy:
	@forge script script/DeployFundMe.s.sol:DeployFundMe $(NETWORK_ARGS)

fund:
	@forge script script/Interactions.s.sol:FundFundMe $(NETWORK_ARGS)

withdraw:
	@forge script script/Interactions.s.sol:WithdrawFundMe $(NETWORK_ARGS)
```

{% endtab %}
{% endtabs %}




---

[Next Page](/llms-full.txt/1)

