Skip to content

Instantly share code, notes, and snippets.

@mds1
Last active July 18, 2024 19:20
Show Gist options
  • Save mds1/3f070676129a095dec372c2d02cedfdd to your computer and use it in GitHub Desktop.
Save mds1/3f070676129a095dec372c2d02cedfdd to your computer and use it in GitHub Desktop.

Revisions

  1. mds1 revised this gist May 11, 2024. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion .ethrc.sh
    Original file line number Diff line number Diff line change
    @@ -231,7 +231,8 @@ getSafeDetails() {

    # Usage: `getOpStackAddresses <L1> <L2> [Contract]` OR `getOpStackAddresses <address>`
    # If one argument is provided, it's an address, and we search the local superchain registry for it.
    # This mode has a depdency on zoxide and ripgrep (https://github.com/ajeetdsouza/zoxide, https://github.com/BurntSushi/ripgrep)
    # NOTE: This mode has hardcoded superchain-registry path you must edit, as well as a dependency on
    # ripgrep (https://github.com/ajeetdsouza/zoxide, https://github.com/BurntSushi/ripgrep)
    # `getOpStackAddresses 0x1234...`
    # If no contract is provided, it will return all contracts:
    # `getOpStackAddresses mainnet op`
  2. mds1 revised this gist May 11, 2024. 1 changed file with 6 additions and 4 deletions.
    10 changes: 6 additions & 4 deletions .ethrc.sh
    Original file line number Diff line number Diff line change
    @@ -242,10 +242,12 @@ getSafeDetails() {
    getOpStackAddresses() {
    if [[ $# -eq 1 ]]; then
    local address="$1"
    dir=$(pwd)
    z superchain-registry
    pwd=$(pwd)
    cd /Users/mds/Documents/projects/superchain-registry || exit
    rg --ignore-case "$address"
    cd "$dir" || exit
    rgExitCode=$?
    cd "$pwd" || exit
    return $rgExitCode
    else
    local REGISTRY_URL=https://raw.githubusercontent.com/ethereum-optimism/superchain-registry/main/superchain/extra/addresses
    local L1="$1"
    @@ -270,4 +272,4 @@ getOpStackAddresses() {
    fi
    fi
    fi
    }
    }
  3. mds1 revised this gist Apr 25, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion .ethrc.sh
    Original file line number Diff line number Diff line change
    @@ -244,7 +244,7 @@ getOpStackAddresses() {
    local address="$1"
    dir=$(pwd)
    z superchain-registry
    rg "$address"
    rg --ignore-case "$address"
    cd "$dir" || exit
    else
    local REGISTRY_URL=https://raw.githubusercontent.com/ethereum-optimism/superchain-registry/main/superchain/extra/addresses
  4. mds1 revised this gist Apr 25, 2024. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions .ethrc.sh
    Original file line number Diff line number Diff line change
    @@ -242,8 +242,10 @@ getSafeDetails() {
    getOpStackAddresses() {
    if [[ $# -eq 1 ]]; then
    local address="$1"
    dir=$(pwd)
    z superchain-registry
    rg "$address"
    cd "$dir" || exit
    else
    local REGISTRY_URL=https://raw.githubusercontent.com/ethereum-optimism/superchain-registry/main/superchain/extra/addresses
    local L1="$1"
  5. mds1 revised this gist Apr 25, 2024. 1 changed file with 25 additions and 17 deletions.
    42 changes: 25 additions & 17 deletions .ethrc.sh
    Original file line number Diff line number Diff line change
    @@ -229,35 +229,43 @@ getSafeDetails() {
    fi
    }

    # Usage: `getOpStackAddresses <L1> <L2> [Contract]`
    # Usage: `getOpStackAddresses <L1> <L2> [Contract]` OR `getOpStackAddresses <address>`
    # If one argument is provided, it's an address, and we search the local superchain registry for it.
    # This mode has a depdency on zoxide and ripgrep (https://github.com/ajeetdsouza/zoxide, https://github.com/BurntSushi/ripgrep)
    # `getOpStackAddresses 0x1234...`
    # If no contract is provided, it will return all contracts:
    # `getOpStackAddresses mainnet op`
    # If a contract is provided and there is an exact match, it will return the address only
    # `getOpStackAddresses mainnet op SystemConfigProxy`
    # If a contract is provided and there are multiple matches, it will return all matches (i.e. fuzzy match)
    # `getOpStackAddresses mainnet op sys`
    getOpStackAddresses() {
    local REGISTRY_URL=https://raw.githubusercontent.com/ethereum-optimism/superchain-registry/main/superchain/extra/addresses
    local L1="$1"
    local L2="$2"
    local Contract="$3"

    if [[ -z "$Contract" ]]; then
    curl --silent "$REGISTRY_URL/$L1/$L2.json" | jq -r
    if [[ $# -eq 1 ]]; then
    local address="$1"
    z superchain-registry
    rg "$address"
    else
    local fuzzyMatch=$(curl --silent "$REGISTRY_URL/$L1/$L2.json" | jq -r "to_entries[] | select(.key | test(\"$Contract\"; \"i\")) | \"\(.key): \(.value)\"")
    local REGISTRY_URL=https://raw.githubusercontent.com/ethereum-optimism/superchain-registry/main/superchain/extra/addresses
    local L1="$1"
    local L2="$2"
    local Contract="$3"
    if [[ -z "$Contract" ]]; then
    curl --silent "$REGISTRY_URL/$L1/$L2.json" | jq -r
    else
    local fuzzyMatch=$(curl --silent "$REGISTRY_URL/$L1/$L2.json" | jq -r "to_entries[] | select(.key | test(\"$Contract\"; \"i\")) | \"\(.key): \(.value)\"")

    if [[ -n "$fuzzyMatch" ]]; then
    local matchCount=$(echo "$fuzzyMatch" | wc -l)
    if [[ -n "$fuzzyMatch" ]]; then
    local matchCount=$(echo "$fuzzyMatch" | wc -l)

    if [[ $matchCount -eq 1 ]]; then
    echo "$fuzzyMatch" | cut -d ':' -f 2 | tr -d ' '
    if [[ $matchCount -eq 1 ]]; then
    echo "$fuzzyMatch" | cut -d ':' -f 2 | tr -d ' '
    else
    echo "$fuzzyMatch"
    fi
    else
    echo "$fuzzyMatch"
    echo "No matching contract found for '$Contract'" >&2
    return 1
    fi
    else
    echo "No matching contract found for '$Contract'" >&2
    return 1
    fi
    fi
    }
  6. mds1 revised this gist Apr 24, 2024. 1 changed file with 33 additions and 0 deletions.
    33 changes: 33 additions & 0 deletions .ethrc.sh
    Original file line number Diff line number Diff line change
    @@ -228,3 +228,36 @@ getSafeDetails() {
    unsetopt ksharrays
    fi
    }

    # Usage: `getOpStackAddresses <L1> <L2> [Contract]`
    # If no contract is provided, it will return all contracts:
    # `getOpStackAddresses mainnet op`
    # If a contract is provided and there is an exact match, it will return the address only
    # `getOpStackAddresses mainnet op SystemConfigProxy`
    # If a contract is provided and there are multiple matches, it will return all matches (i.e. fuzzy match)
    # `getOpStackAddresses mainnet op sys`
    getOpStackAddresses() {
    local REGISTRY_URL=https://raw.githubusercontent.com/ethereum-optimism/superchain-registry/main/superchain/extra/addresses
    local L1="$1"
    local L2="$2"
    local Contract="$3"

    if [[ -z "$Contract" ]]; then
    curl --silent "$REGISTRY_URL/$L1/$L2.json" | jq -r
    else
    local fuzzyMatch=$(curl --silent "$REGISTRY_URL/$L1/$L2.json" | jq -r "to_entries[] | select(.key | test(\"$Contract\"; \"i\")) | \"\(.key): \(.value)\"")

    if [[ -n "$fuzzyMatch" ]]; then
    local matchCount=$(echo "$fuzzyMatch" | wc -l)

    if [[ $matchCount -eq 1 ]]; then
    echo "$fuzzyMatch" | cut -d ':' -f 2 | tr -d ' '
    else
    echo "$fuzzyMatch"
    fi
    else
    echo "No matching contract found for '$Contract'" >&2
    return 1
    fi
    fi
    }
  7. mds1 revised this gist Feb 28, 2024. 1 changed file with 155 additions and 41 deletions.
    196 changes: 155 additions & 41 deletions .ethrc.sh
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,42 @@
    # Ethereum helper methods
    # source this in your .bashrc or .zshrc file with `. ~/.ethrc`

    # --- Solidity sandbox ---
    # https://github.com/maurelian/solidity-sandbox
    scratch() {
    dir=$(pwd)
    cd ~/Documents/projects/solidity-sandbox || exit
    bash newTest.sh $1
    cd "$dir" || exit
    }

    # --- Forge helers ---
    alias f="forge"

    # Aliases to local foundry binaries .
    alias forgel="~/prj/foundry-rs/foundry/target/debug/forge"
    alias castl="~/prj/foundry-rs/foundry/target/debug/cast"
    alias anvill="~/prj/foundry-rs/foundry/target/debug/anvil"
    alias chisell="~/prj/foundry-rs/foundry/target/debug/chisel"
    alias scopelintl="~/prj/scopelint/target/debug/scopelint"
    alias bulloakl="~/prj/bulloak/target/debug/bulloak"

    # Update foundry and install shell completions:
    # - https://book.getfoundry.sh/config/shell-autocompletion
    # - https://twitter.com/0xyyy_/status/1562091599731228672
    # We use a function then alias `gm` to it so we can override the
    # `alias gm="git merge"` that exists in the ohmyzsh git plugin.
    FOUNDRY_PLUGIN_DIR=${ZSH_CUSTOM:-${ZSH:-~/.oh-my-zsh}/custom}/plugins/foundry
    fpath+=$FOUNDRY_PLUGIN_DIR
    updateFoundry() {
    foundryup "$@"
    mkdir -p $FOUNDRY_PLUGIN_DIR
    anvil completions zsh > $FOUNDRY_PLUGIN_DIR/_anvil
    cast completions zsh > $FOUNDRY_PLUGIN_DIR/_cast
    forge completions zsh > $FOUNDRY_PLUGIN_DIR/_forge
    }
    alias gm="updateFoundry"

    # --- Token addresses ---
    aave=0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9
    comp=0xc00e94Cb662C3520282E6f5717214004A7f26888
    @@ -17,6 +53,12 @@ usdt=0xdAC17F958D2ee523a2206206994597C13D831ec7
    wbtc=0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599
    weth=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
    yfi=0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e
    zero=0x0000000000000000000000000000000000000000

    # --- Contracts ---
    umbra=0xFb2dc580Eed955B528407b4d36FfaFe3da685401
    stealthKeyRegistry=0x31fe56609C65Cd0C510E7125f051D440424D38f3
    multicall=0xcA11bde05977b3631167028862bE2a173976CA11

    # --- Prices / gas ---
    # Returns the price in USD of the specified token
    @@ -36,45 +78,80 @@ price() {
    gas() {
    wad=1000000000000000000 # 1e18
    price_eth=$(price eth)
    price_gas=$(seth basefee)
    price_gas_gwei=$(seth --to-fix 9 $price_gas)
    cost_transfer=$(echo "scale=10;$price_eth*$price_gas*21000/$wad" | bc) # ETH transfer
    cost_swap=$(echo "scale=10;$price_eth*$price_gas*130000/$wad" | bc) # Uniswap V3 swap
    cost_deploy=$(echo "scale=10;$price_eth*$price_gas*1000000/$wad" | bc) # Something expensive, like contract deployment
    printf 'Basefee \t%1.3f\n' $price_gas_gwei
    price_gas=$(cast base-fee)
    price_gas_gwei=$(cast --to-fix 9 "$price_gas")

    # Calculating costs in USD
    cost_transfer_usd=$(echo "scale=10;$price_eth*$price_gas*21000/$wad" | bc) # ETH transfer cost in USD
    cost_swap_usd=$(echo "scale=10;$price_eth*$price_gas*130000/$wad" | bc) # Uniswap V3 swap cost in USD
    cost_deploy_usd=$(echo "scale=10;$price_eth*$price_gas*1000000/$wad" | bc) # Contract deployment cost in USD

    # Calculating costs in ETH
    cost_transfer_eth=$(echo "scale=10;$price_gas*21000/$wad" | bc) # ETH transfer cost in ETH
    cost_swap_eth=$(echo "scale=10;$price_gas*130000/$wad" | bc) # Uniswap V3 swap cost in ETH
    cost_deploy_eth=$(echo "scale=10;$price_gas*1000000/$wad" | bc) # Contract deployment cost in ETH

    printf 'ETH price \t%1.3f USD\n' "$price_eth"
    printf 'Basefee \t%1.3f gwei\n' "$price_gas_gwei"
    echo ""
    printf 'Transfer \t21k gas \t $%1.3f\n' $cost_transfer
    printf 'Swap \t130k gas \t $%1.3f\n' $cost_swap
    printf 'Deploy \t1M gas \t $%1.3f\n' $cost_deploy
    printf 'Transfer \t21k gas \t $%1.3f \t%1.5f ETH\n' "$cost_transfer_usd" "$cost_transfer_eth"
    printf 'Swap \t130k gas \t $%1.3f \t%1.5f ETH\n' "$cost_swap_usd" "$cost_swap_eth"
    printf 'Deploy \t1M gas \t $%1.3f \t%1.5f ETH\n' "$cost_deploy_usd" "$cost_deploy_eth"
    }

    # --- 4byte lookups ---
    # https://www.4byte.directory/docs/
    # --- ERC-20 Calls ---
    # example: `name <token>`
    # example: `name $dai`
    name() {
    cast call "$1" "name()(string)"
    }

    # Pass in a 4 byte function signature and get matching functions from 4byte.directory. This will also strip
    # any appended calldata after the first four bytes
    # example: `4byte 0x70a08231`
    # example: `4byte 0xa9059cbb000000000000000000000000ae804d5b383350c487748c364ad7ec8f480e5b63000000000000000000000000000000000000000000000660a546d2d9a8e73ce3`
    4byte() {
    curl -s "https://www.4byte.directory/api/v1/signatures/?hex_signature=${1:0:10}" | jq .
    # example: `symbol <token>`
    symbol() {
    cast call "$1" "symbol()(string)"
    }

    # Pass in a 32 byte topic and get matching events from 4byte.directory
    # example: `4byteEvent 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef`
    4byteEvent() {
    curl -s "https://www.4byte.directory/api/v1/event-signatures/?hex_signature=$1" | jq .
    # example: `decimals <token>`
    decimals() {
    cast call "$1" "decimals()(uint8)"
    }

    # --- Calls ---
    # example: `balanceOf <token> <address>`
    # example: `balanceOf $dai <address>`
    balanceOf() {
    seth call $1 "balanceOf(address)(uint256)" $2
    balanceOf() {
    cast call "$1" "balanceOf(address)(uint256)" "$2"
    }

    # example: `allowance <token> <holder> <spender>`
    allowance() {
    cast call "$1" "allowance(address,address)(uint256)" "$2" "$3"
    }

    # example: `totalSupply <token>`
    totalSupply() {
    cast call "$1" "totalSupply()(uint256)"
    }

    interface() {
    if [[ $1 == 0x* ]]; then
    cast interface "$1" -c "${2:-mainnet}" --etherscan-api-key "${3:-$ETHERSCAN_API_KEY}"
    else
    cast interface <(forge inspect "$1" abi)
    fi
    }

    # --- Seth/Cast helpers ---
    # checksums the address
    checksum() {
    cast --to-checksum-address "$1"
    }

    # checksums the address and copies it to the clipboard (after deleting any new lines characters)
    checksumc() {
    cast --to-checksum-address "$1" | tr -d '\n' | pbcopy
    }

    # --- Seth helpers ---
    # returns the basefee in gwei
    alias basefee='seth --from-wei $(seth basefee) gwei'
    alias basefee='cast --from-wei $(cast basefee) gwei'

    # example: `tracetx <txhash>` (`trace` is a builtin command)
    tracetx() {
    @@ -88,20 +165,6 @@ debug() {
    rm tmp.json # <toContractName>.sol is often leftover, so delete that manually afterwards
    }

    # Returns the function selector for given data
    # example: `selector <sig>`
    selector() {
    hash=$(seth keccak $1)
    echo ${hash:0:10}
    }

    # ABI encode values, and return encoded values without the function signature
    # example: `abiEncode <sig> [<args>]`
    abiEncode() {
    x=$(seth calldata $@);
    echo "0x${x:10}" # slice off the function signature, i.e. provided function name doesn't matter
    }

    # Returns the slot used to store the value of a Solidity mapping for a specified address
    # example: `getSolidityAddressSlot <address> <mappingSlot>`
    getSolidityAddressSlot() {
    @@ -114,3 +177,54 @@ getSolidityAddressSlot() {
    getVyperAddressSlot() {
    echo $(seth keccak $(abiEncode "x(uint256,address)" $2 $1))
    }

    # Usage `getSafeDetails <safe-address> [cast call options]`
    # All `cast call` options are passed to `cast call` commands. The one
    # exception is when we do ENS lookups, in which case we ignore cast flags
    # and always use the latest block with a mainnet RPC URL. This is done by
    # assuming a `MAINNET_RPC_URL` env var is set.
    getSafeDetails() {
    local safe=$1
    shift # Shift the first argument off so "$@" contains any additional arguments

    local threshold owners nonce

    # Ensure compatibility with both bash and zsh for arrays.
    # In zsh, arrays start at 1 by default and it handles word splitting differently.
    # Setting KSH_ARRAYS makes array indexing start at 0 in zsh, similar to bash,
    # and we disable it at the end of the function.
    if [[ -n "$ZSH_VERSION" ]]; then
    setopt localoptions ksharrays
    fi

    nonce=$(cast call "$safe" "nonce()(uint256)" "$@")
    threshold=$(cast call "$safe" "getThreshold()(uint256)" "$@")
    owners=$(cast call "$safe" "getOwners()(address[])" "$@" | tr -d '[]' | tr ',' '\n')

    # Convert string to array.
    # This works in both bash and zsh without needing to change IFS.
    local ownersArray=()
    while IFS= read -r line; do
    ownersArray+=("$line")
    done <<< "$owners"

    echo "Current Nonce: $nonce"
    echo "Threshold: $threshold"
    echo "Number of Owners: ${#ownersArray[@]}"

    # Lookup each owner address
    for address in "${ownersArray[@]}"; do
    address="${address#"${address%%[![:space:]]*}"}" # remove leading whitespace
    ownerName=$(cast lookup-address "$address" -r "$MAINNET_RPC_URL" 2>/dev/null)
    if [[ -n $ownerName ]]; then
    echo " $address $ownerName"
    else
    echo " $address"
    fi
    done

    # If previously set KSH_ARRAYS for zsh, unset it to revert back to normal zsh behavior
    if [[ -n "$ZSH_VERSION" ]]; then
    unsetopt ksharrays
    fi
    }
  8. mds1 revised this gist Sep 10, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion .ethrc.sh
    Original file line number Diff line number Diff line change
    @@ -74,7 +74,7 @@ balanceOf() {

    # --- Seth helpers ---
    # returns the basefee in gwei
    alias basefee="seth --from-wei $(seth basefee) gwei"
    alias basefee='seth --from-wei $(seth basefee) gwei'

    # example: `tracetx <txhash>` (`trace` is a builtin command)
    tracetx() {
  9. mds1 revised this gist Aug 24, 2021. 1 changed file with 7 additions and 0 deletions.
    7 changes: 7 additions & 0 deletions .ethrc.sh
    Original file line number Diff line number Diff line change
    @@ -88,6 +88,13 @@ debug() {
    rm tmp.json # <toContractName>.sol is often leftover, so delete that manually afterwards
    }

    # Returns the function selector for given data
    # example: `selector <sig>`
    selector() {
    hash=$(seth keccak $1)
    echo ${hash:0:10}
    }

    # ABI encode values, and return encoded values without the function signature
    # example: `abiEncode <sig> [<args>]`
    abiEncode() {
  10. mds1 created this gist Aug 23, 2021.
    109 changes: 109 additions & 0 deletions .ethrc.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,109 @@
    # Ethereum helper methods
    # source this in your .bashrc or .zshrc file with `. ~/.ethrc`

    # --- Token addresses ---
    aave=0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9
    comp=0xc00e94Cb662C3520282E6f5717214004A7f26888
    crv=0xD533a949740bb3306d119CC777fa900bA034cd52
    dai=0x6B175474E89094C44Da98b954EedeAC495271d0F
    gtc=0xDe30da39c46104798bB5aA3fe8B9e0e1F348163F
    mkr=0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2
    snx=0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F
    tbtc=0x8dAEBADE922dF735c38C80C7eBD708Af50815fAa
    uni=0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984
    usdc=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
    usdn=0x674C6Ad92Fd080e4004b2312b45f796a192D27a0
    usdt=0xdAC17F958D2ee523a2206206994597C13D831ec7
    wbtc=0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599
    weth=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
    yfi=0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e

    # --- Prices / gas ---
    # Returns the price in USD of the specified token
    # https://www.coingecko.com/en/api/documentation
    # example: `price eth`
    # example: `price $gtc`
    # example: `price <token>`
    price() {
    if [[ $1 = 'eth' ]]; then
    echo $(curl -s https://api.coingecko.com/api/v3/simple/price\?ids\=ethereum\&vs_currencies\=usd | jq '.ethereum.usd')
    else
    echo $(curl -s https://api.coingecko.com/api/v3/coins/ethereum/contract/$1 | jq '.market_data.current_price.usd')
    fi
    }

    # prints the basefee in gwei, and the cost in USD of sending transactions based on current basefee and no priority fee
    gas() {
    wad=1000000000000000000 # 1e18
    price_eth=$(price eth)
    price_gas=$(seth basefee)
    price_gas_gwei=$(seth --to-fix 9 $price_gas)
    cost_transfer=$(echo "scale=10;$price_eth*$price_gas*21000/$wad" | bc) # ETH transfer
    cost_swap=$(echo "scale=10;$price_eth*$price_gas*130000/$wad" | bc) # Uniswap V3 swap
    cost_deploy=$(echo "scale=10;$price_eth*$price_gas*1000000/$wad" | bc) # Something expensive, like contract deployment
    printf 'Basefee \t%1.3f\n' $price_gas_gwei
    echo ""
    printf 'Transfer \t21k gas \t $%1.3f\n' $cost_transfer
    printf 'Swap \t130k gas \t $%1.3f\n' $cost_swap
    printf 'Deploy \t1M gas \t $%1.3f\n' $cost_deploy
    }

    # --- 4byte lookups ---
    # https://www.4byte.directory/docs/

    # Pass in a 4 byte function signature and get matching functions from 4byte.directory. This will also strip
    # any appended calldata after the first four bytes
    # example: `4byte 0x70a08231`
    # example: `4byte 0xa9059cbb000000000000000000000000ae804d5b383350c487748c364ad7ec8f480e5b63000000000000000000000000000000000000000000000660a546d2d9a8e73ce3`
    4byte() {
    curl -s "https://www.4byte.directory/api/v1/signatures/?hex_signature=${1:0:10}" | jq .
    }

    # Pass in a 32 byte topic and get matching events from 4byte.directory
    # example: `4byteEvent 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef`
    4byteEvent() {
    curl -s "https://www.4byte.directory/api/v1/event-signatures/?hex_signature=$1" | jq .
    }

    # --- Calls ---
    # example: `balanceOf <token> <address>`
    # example: `balanceOf $dai <address>`
    balanceOf() {
    seth call $1 "balanceOf(address)(uint256)" $2
    }

    # --- Seth helpers ---
    # returns the basefee in gwei
    alias basefee="seth --from-wei $(seth basefee) gwei"

    # example: `tracetx <txhash>` (`trace` is a builtin command)
    tracetx() {
    seth run-tx $1 --trace
    }

    # example: `debug <txhash>`
    debug() {
    seth bundle-source $(seth tx $1 to) > tmp.json && \ # often might need to bundle other sources
    seth run-tx $1 --source=tmp.json --debug && \
    rm tmp.json # <toContractName>.sol is often leftover, so delete that manually afterwards
    }

    # ABI encode values, and return encoded values without the function signature
    # example: `abiEncode <sig> [<args>]`
    abiEncode() {
    x=$(seth calldata $@);
    echo "0x${x:10}" # slice off the function signature, i.e. provided function name doesn't matter
    }

    # Returns the slot used to store the value of a Solidity mapping for a specified address
    # example: `getSolidityAddressSlot <address> <mappingSlot>`
    getSolidityAddressSlot() {
    echo $(seth keccak $(abiEncode "x(address,uint256)" $1 $2))
    }

    # Returns the slot used to store the value of a Vyper mapping for a specified address
    # note: not guaranteed to work for all Vyper versions since storage layout is not yet stable. More info: https://twitter.com/big_tech_sux/status/1420159854170152963
    # example: `getVyperAddressSlot <address> <mappingSlot>`
    getVyperAddressSlot() {
    echo $(seth keccak $(abiEncode "x(uint256,address)" $2 $1))
    }