Last active
July 18, 2024 19:20
-
-
Save mds1/3f070676129a095dec372c2d02cedfdd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 | |
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 | |
zero=0x0000000000000000000000000000000000000000 | |
# --- Contracts --- | |
umbra=0xFb2dc580Eed955B528407b4d36FfaFe3da685401 | |
stealthKeyRegistry=0x31fe56609C65Cd0C510E7125f051D440424D38f3 | |
multicall=0xcA11bde05977b3631167028862bE2a173976CA11 | |
# --- 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=$(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 \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" | |
} | |
# --- ERC-20 Calls --- | |
# example: `name <token>` | |
# example: `name $dai` | |
name() { | |
cast call "$1" "name()(string)" | |
} | |
# example: `symbol <token>` | |
symbol() { | |
cast call "$1" "symbol()(string)" | |
} | |
# example: `decimals <token>` | |
decimals() { | |
cast call "$1" "decimals()(uint8)" | |
} | |
# example: `balanceOf <token> <address>` | |
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 | |
} | |
# returns the basefee in gwei | |
alias basefee='cast --from-wei $(cast 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 | |
} | |
# 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)) | |
} | |
# 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 | |
} | |
# 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. | |
# 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` | |
# 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() { | |
if [[ $# -eq 1 ]]; then | |
local address="$1" | |
pwd=$(pwd) | |
cd /Users/mds/Documents/projects/superchain-registry || exit | |
rg --ignore-case "$address" | |
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" | |
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 | |
fi | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Updates to use TOML in the registry mean that code should look more like this now: