Compare commits

...

5 Commits

Author SHA1 Message Date
Nikhil Suri 09ff54ebd5
Merge c08336f440 into d63f2ca532 2024-04-26 10:27:03 -04:00
Dirk Brink d63f2ca532 node: Manual initial token list for Blast and Scroll 2024-04-26 09:48:21 -04:00
Evan Gray e6dfb9115e node: shorten hostname for load testing 2024-04-25 16:11:57 -04:00
bruce-riley 034c570b33
Node/Acct: Add parameter checks (#3907) 2024-04-25 15:10:01 -05:00
Nikhil Suri c08336f440 ethereum: script to simulate governance for NTT 2024-04-23 22:04:08 -07:00
4 changed files with 282 additions and 1 deletions

View File

@ -0,0 +1,235 @@
#!/bin/bash
set -euo pipefail
# This script ensures that the EVM contracts can be safely upgraded to without
# bricking the contracts. It does this by simulating contract upgrades against
# the mainnet state, and checks that the state is consistent after the upgrade.
#
# By default, the script will compile the contracts and run the upgrade. It's
# possible to simulate an upgrade against an already deployed implementation
# contract (which is useful for independent verification of a governance
# proposal) -- see the usage instructions below.
function usage() {
cat <<EOF >&2
Usage:
$(basename "$0") [-h] [-c s] [-x] [-k] [-l s] -- Simulate an upgrade on a fork of mainnet, and check for any errors.
where:
-h show this help text
-c chain name
-x run anvil
-k keep anvil alive
-l file to log to (by default creates a new tmp file)
EOF
exit 1
}
before=$(mktemp)
after=$(mktemp)
### Parse command line options
chain_name=""
run_anvil=false
keepalive_anvil=false
anvil_out=$(mktemp)
while getopts ':h:c::xkl' option; do
case "$option" in
h) usage
;;
c) chain_name=$OPTARG
;;
x) run_anvil=true
;;
l) anvil_out=$OPTARG
;;
k) keepalive_anvil=true
run_anvil=true
;;
:) printf "missing argument for -%s\n" "$OPTARG" >&2
usage
;;
\?) printf "illegal option: -%s\n" "$OPTARG" >&2
usage
;;
esac
done
shift $((OPTIND - 1))
# Check that we have the required arguments
[ -z "$chain_name" ] && usage
# Get core contract address
CORE=$(worm info contract mainnet "$chain_name" Core)
printf "Wormhole Core Contract: $CORE\n\n"
# Use the local devnet guardian key (this is not a production key)
GUARDIAN_ADDRESS=0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe
GUARDIAN_SECRET=cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0
ANVIL_PID=""
function clean_up () {
ARG=$?
[ -n "$ANVIL_PID" ] && kill "$ANVIL_PID"
exit $ARG
}
trap clean_up SIGINT SIGTERM EXIT
#TODO: make RPC an optional argument
USER_ADDRESS=90F8bf6A479f320ead074411a4B0e7944Ea8c9C1
USER_PK=0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d
HOST="http://0.0.0.0"
PORT="8545"
RPC="$HOST:$PORT"
if [[ $run_anvil = true ]]; then
./anvil_fork "$chain_name"
ANVIL_PID=$!
echo "🍴 Forking mainnet..."
echo "Anvil logs in $anvil_out"
sleep 5
ps | grep "$ANVIL_PID"
fi
GOV_CONTRACT=""
NTT_CONTRACT=""
UNSIGNED_PAUSE_VAA=""
UNSIGNED_UNPAUSE_VAA=""
case "$chain_name" in
ethereum)
GOV_CONTRACT=0x23Fea5514DFC9821479fBE18BA1D7e1A61f6FfCf
NTT_CONTRACT=0xc072B1AEf336eDde59A049699Ef4e8Fa9D594A48
UNSIGNED_PAUSE_VAA=0100000004000000000076fc210a00010000000000000000000000000000000000000000000000000000000000000004f6ca212aede81c0a20000000000000000047656e6572616c507572706f7365476f7665726e616e636501000223fea5514dfc9821479fbe18ba1d7e1a61f6ffcfc072b1aef336edde59a049699ef4e8fa9d594a4800048456cb59
UNSIGNED_UNPAUSE_VAA=010000000400000000002d25e93f000100000000000000000000000000000000000000000000000000000000000000044af9d5923779bdf520000000000000000047656e6572616c507572706f7365476f7665726e616e636501000223fea5514dfc9821479fbe18ba1d7e1a61f6ffcfc072b1aef336edde59a049699ef4e8fa9d594a4800043f4ba83a
;;
arbitrum)
GOV_CONTRACT=0x36CF4c88FA548c6Ad9fcDc696e1c27Bb3306163F
NTT_CONTRACT=0x5333d0AcA64a450Add6FeF76D6D1375F726CB484
UNSIGNED_PAUSE_VAA=01000000040000000000a97c5ba800010000000000000000000000000000000000000000000000000000000000000004efd07b35d2dd420a20000000000000000047656e6572616c507572706f7365476f7665726e616e636501001736cf4c88fa548c6ad9fcdc696e1c27bb3306163f5333d0aca64a450add6fef76d6d1375f726cb48400048456cb59
UNSIGNED_UNPAUSE_VAA=0100000004000000000092654e5000010000000000000000000000000000000000000000000000000000000000000004529039baf463475220000000000000000047656e6572616c507572706f7365476f7665726e616e636501001736cf4c88fa548c6ad9fcdc696e1c27bb3306163f5333d0aca64a450add6fef76d6d1375f726cb48400043f4ba83a
;;
optimism)
GOV_CONTRACT=0x0E09a3081837ff23D2e59B179E0Bc48A349Afbd8
NTT_CONTRACT=0x1a4F1a790f23Ffb9772966cB6F36dCd658033e13
UNSIGNED_PAUSE_VAA=01000000040000000000952b3208000100000000000000000000000000000000000000000000000000000000000000042a5d763e56b1709d20000000000000000047656e6572616c507572706f7365476f7665726e616e63650100180e09a3081837ff23d2e59b179e0bc48a349afbd81a4f1a790f23ffb9772966cb6f36dcd658033e1300048456cb59
UNSIGNED_UNPAUSE_VAA=01000000040000000000fe7d99ea00010000000000000000000000000000000000000000000000000000000000000004a3d4945c1212065020000000000000000047656e6572616c507572706f7365476f7665726e616e63650100180e09a3081837ff23d2e59b179e0bc48a349afbd81a4f1a790f23ffb9772966cb6f36dcd658033e1300043f4ba83a
;;
base)
GOV_CONTRACT=0x838a95B6a3E06B6f11C437e22f3C7561a6ec40F1
NTT_CONTRACT=0x5333d0AcA64a450Add6FeF76D6D1375F726CB484
UNSIGNED_PAUSE_VAA=010000000400000000008f3da7570001000000000000000000000000000000000000000000000000000000000000000458191dc4234221d420000000000000000047656e6572616c507572706f7365476f7665726e616e636501001e838a95b6a3e06b6f11c437e22f3c7561a6ec40f15333d0aca64a450add6fef76d6d1375f726cb48400048456cb59
UNSIGNED_UNPAUSE_VAA=010000000400000000000498f2cd00010000000000000000000000000000000000000000000000000000000000000004a1cc2db10977351720000000000000000047656e6572616c507572706f7365476f7665726e616e636501001e838a95b6a3e06b6f11c437e22f3c7561a6ec40f15333d0aca64a450add6fef76d6d1375f726cb48400043f4ba83a
;;
*) echo "unknown module $module" >&2
usage
;;
esac
# Step 0) the VAAs are not compatible with the guardian
# set on mainnet (since that corresponds to a mainnet guardian network). We need
# to thus locally replace the guardian set with the local guardian key.
echo "STEP 0:"
echo "💂 Overriding guardian set with $GUARDIAN_ADDRESS"
worm evm hijack -g "$GUARDIAN_ADDRESS" -i 0 -a "$CORE" --rpc "$RPC"> /dev/null
printf "\n\n"
# Step 0.5) override the pauser and owner to be our devnet address
echo "STEP 0.5:"
echo "Overriding owner and pauser to be default anvil address..."
$(cast rpc anvil_setStorageAt "$NTT_CONTRACT" 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300 "0x000000000000000000000000${USER_ADDRESS}")
$(cast rpc anvil_setStorageAt "$NTT_CONTRACT" 0xBFA91572CE1E5FE8776A160D3B1F862E83F5EE2C080A7423B4761602A3AD1249 "0x000000000000000000000000${USER_ADDRESS}")
printf "Done\n\n"
# Step 0.75) Resign the pause and unpause VAAs with the devnet guardian secret
pauseVaa=$(worm edit-vaa --network devnet --gs $GUARDIAN_SECRET --vaa $UNSIGNED_PAUSE_VAA)
unpauseVaa=$(worm edit-vaa --network devnet --gs $GUARDIAN_SECRET --vaa $UNSIGNED_UNPAUSE_VAA)
# Step 1) Query owner and pauser for the current NTT Manager contract (should not be the governance contract)
echo "STEP 1:"
echo "Getting owner and pauser for NTT Manager..."
owner=$(cast call "$NTT_CONTRACT" "owner()(address)")
pauser=$(cast call "$NTT_CONTRACT" "pauser()(address)")
if [[ $owner != "0x${USER_ADDRESS}" ]] || [[ $pauser != "0x${USER_ADDRESS}" ]]; then
echo "ERROR! Owner is $owner and pauser is $pauser, which is unexpected! Exiting..."
clean_up
else
printf "Verified owner and pauser are expected as $owner\n\n"
fi
# Step 2) Transfer ownership of the NTT Manager contract to the Governance contract
echo "STEP 2:"
echo "Transferring ownership to Governance Contract..."
cast send --private-key "$USER_PK" "$NTT_CONTRACT" "transferOwnership(address)" "$GOV_CONTRACT"
cast send --private-key "$USER_PK" "$NTT_CONTRACT" "transferPauserCapability(address)" "$GOV_CONTRACT"
printf "Done\n\n"
# Step 3) Query owner and pauser of the NTT Manager contract (should be the governance contract)
echo "STEP 3:"
echo "Getting owner and pauser for NTT Manager (should both be "$GOV_CONTRACT")..."
owner=$(cast call "$NTT_CONTRACT" "owner()(address)")
pauser=$(cast call "$NTT_CONTRACT" "pauser()(address)")
if [[ $owner != $GOV_CONTRACT ]] || [[ $pauser != $GOV_CONTRACT ]]; then
echo "ERROR! Both owner and pauser should be governance contract! Exiting..."
clean_up
else
printf "Verified owner and pauser are governance contract $GOV_CONTRACT\n\n"
fi
# Step 4) Query paused state is UNPAUSED on NTT Manager
echo "STEP 4:"
echo "Getting paused state on NTT Manager... (should be 0x01 or UNPAUSED)"
isPaused=$(cast call "$NTT_CONTRACT" "isPaused()(bool)")
if [[ $isPaused != false ]]; then
echo "ERROR! Contract should not be paused. Exiting..."
clean_up
else
printf "Verified contract is not paused\n\n"
fi
# Step 5) Submit Pause VAA to Manager via Governance contract
echo "STEP 5:"
echo "Submitting Pause VAA to Governance contract..."
cast send --private-key "$USER_PK" "$GOV_CONTRACT" "performGovernance(bytes)" "$pauseVaa"
printf "Done\n\n"
# Step 6) Query paused state is PAUSED on NTT Manager
echo "STEP 6:"
echo "Getting paused state on NTT Manager... (should be 0x02 or PAUSED)"
isPaused=$(cast call "$NTT_CONTRACT" "isPaused()(bool)")
if [[ $isPaused != true ]]; then
echo "ERROR! Contract should be paused. Exiting..."
clean_up
else
printf "Verified contract is paused\n\n"
fi
# Step 7) Submit Unpause VAA to Manager via Governance contract
echo "STEP 7:"
echo "Submitting Unpause VAA to Governance contract..."
cast send --private-key "$USER_PK" "$GOV_CONTRACT" "performGovernance(bytes)" "$unpauseVaa"
printf "Done\n\n"
# Step 8) Query paused state is UNPAUSED on NTT Manager
echo "STEP 8:"
echo "Getting paused state on NTT Manager... (should be 0x01 or UNPAUSED)"
isPaused=$(cast call "$NTT_CONTRACT" "isPaused()(bool)")
if [[ $isPaused != false ]]; then
echo "ERROR! Contract should not be paused. Exiting..."
clean_up
else
printf "Verified contract is not paused\n\n"
fi
echo "Congratulations! You've verified that the Governance contract works in a mainnet fork test."
# Anvil can be kept alive by setting the -k flag. This is useful for interacting
# with the contract after it has been upgraded.
if [[ $keepalive_anvil = true ]]; then
echo "Listening on $RPC"
# tail -f "$anvil_out"
wait "$ANVIL_PID"
fi

View File

@ -1003,10 +1003,16 @@ func runNode(cmd *cobra.Command, args []string) {
if idx != 0 {
// try to connect to guardian-0
for {
// tilt uses this hostname format
_, err := net.LookupIP("guardian-0.guardian")
if err == nil {
break
}
// load tests use this hostname format
_, err = net.LookupIP("guardian-0")
if err == nil {
break
}
logger.Info("Error resolving guardian-0.guardian. Trying again...")
time.Sleep(time.Second)
}
@ -1151,6 +1157,10 @@ func runNode(cmd *cobra.Command, args []string) {
var accountantWormchainConn, accountantNttWormchainConn *wormconn.ClientConn
if *accountantContract != "" {
if *wormchainURL == "" {
logger.Fatal("if accountantContract is specified, wormchainURL is required", zap.String("component", "gacct"))
}
if *accountantKeyPath == "" {
logger.Fatal("if accountantContract is specified, accountantKeyPath is required", zap.String("component", "gacct"))
}
@ -1183,6 +1193,10 @@ func runNode(cmd *cobra.Command, args []string) {
// If the NTT accountant is enabled, create a wormchain connection for it.
if *accountantNttContract != "" {
if *wormchainURL == "" {
logger.Fatal("if accountantNttContract is specified, wormchainURL is required", zap.String("component", "gacct"))
}
if *accountantNttKeyPath == "" {
logger.Fatal("if accountantNttContract is specified, accountantNttKeyPath is required", zap.String("component", "gacct"))
}

View File

@ -14,5 +14,37 @@ func manualTokenList() []tokenConfigEntry {
{chain: 13, addr: "0000000000000000000000005096db80b21ef45230c9e423c373f1fc9c0198dd", symbol: "WEMIX", coinGeckoId: "wemix-token", decimals: 8, price: 1.74},
{chain: 15, addr: "0000000000000000000000000000000000000000000000000000000000000000", symbol: "NEAR", coinGeckoId: "near", decimals: 8, price: 3.85},
{chain: 32, addr: "00881043998ff2b738519d444d2dd0da3da4545de08290c1076746538d5333df", symbol: "Sei", coinGeckoId: "sei-network", decimals: 6, price: 0.0},
// BLAST (tokens over $50,000 24h volume)
{chain: 36, addr: "0000000000000000000000004300000000000000000000000000000000000003", symbol: "USDB", coinGeckoId: "usdb", decimals: 18, price: 1.00},
{chain: 36, addr: "0000000000000000000000004300000000000000000000000000000000000004", symbol: "WETH", coinGeckoId: "weth", decimals: 18, price: 3157.42},
{chain: 36, addr: "0000000000000000000000002416092f143378750bb29b79ed961ab195cceea5", symbol: "EZETH", coinGeckoId: "renzo-restaked-eth", decimals: 18, price: 3092.32},
{chain: 36, addr: "0000000000000000000000004fee793d435c6d2c10c135983bb9d6d4fc7b9bbd", symbol: "USD+", coinGeckoId: "usd", decimals: 18, price: 1.00},
{chain: 36, addr: "000000000000000000000000818a92bc81aad0053d72ba753fb5bc3d0c5c0923", symbol: "JUICE", coinGeckoId: "juice-finance", decimals: 18, price: 0.1051},
{chain: 36, addr: "0000000000000000000000009e20461bc2c4c980f62f1b279d71734207a6a356", symbol: "OMNI", coinGeckoId: "omnicat", decimals: 18, price: 0.0004575},
{chain: 36, addr: "000000000000000000000000764933fbad8f5d04ccd088602096655c2ed9879f", symbol: "AI", coinGeckoId: "any-inu", decimals: 18, price: 0.00002742},
{chain: 36, addr: "0000000000000000000000005ffd9ebd27f2fcab044c0f0a26a45cb62fa29c06", symbol: "PAC", coinGeckoId: "pacmoon", decimals: 18, price: 0.05459},
{chain: 36, addr: "00000000000000000000000020fe91f17ec9080e3cac2d688b4ecb48c5ac3a9c", symbol: "YES", coinGeckoId: "yes-money", decimals: 18, price: 3.96},
{chain: 36, addr: "00000000000000000000000076da31d7c9cbeae102aff34d3398bc450c8374c1", symbol: "MIM", coinGeckoId: "magic-internet-money", decimals: 18, price: 0.9935},
{chain: 36, addr: "00000000000000000000000015d24de366f69b835be19f7cf9447e770315dd80", symbol: "KAP", coinGeckoId: "kapital-dao", decimals: 18, price: 0.1143},
{chain: 36, addr: "000000000000000000000000b9dfcd4cf589bb8090569cb52fac1b88dbe4981f", symbol: "BAG", coinGeckoId: "bag", decimals: 18, price: 0.002972},
{chain: 36, addr: "00000000000000000000000068449870eea84453044bd430822827e21fd8f101", symbol: "ZAI", coinGeckoId: "zaibot", decimals: 18, price: 0.2348},
{chain: 36, addr: "00000000000000000000000047c337bd5b9344a6f3d6f58c474d9d8cd419d8ca", symbol: "DACKIE", coinGeckoId: "dackieswap", decimals: 18, price: 0.006554},
{chain: 36, addr: "000000000000000000000000d43d8adac6a4c7d9aeece7c3151fca8f23752cf8", symbol: "ANDY", coinGeckoId: "andyerc", decimals: 9, price: 0.1165},
{chain: 36, addr: "00000000000000000000000087e154e86fb691ab8a27116e93ed8d54e2b8c18c", symbol: "TES", coinGeckoId: "titan-trading-token", decimals: 18, price: 0.867},
{chain: 36, addr: "000000000000000000000000870a8f46b62b8bdeda4c02530c1750cddf2ed32e", symbol: "USDC+", coinGeckoId: "usdc-plus-overnight", decimals: 18, price: 1.00},
{chain: 36, addr: "00000000000000000000000042e12d42b3d6c4a74a88a61063856756ea2db357", symbol: "ORBIT", coinGeckoId: "orbit-protocol", decimals: 18, price: 0.3074},
// SCROLL (tokens over $50,000 24h volume)
{chain: 34, addr: "0000000000000000000000000018d96c579121a94307249d47f053e2d687b5e7", symbol: "MVX", coinGeckoId: "metavault-trade", decimals: 18, price: 2.06},
{chain: 34, addr: "00000000000000000000000047c337bd5b9344a6f3d6f58c474d9d8cd419d8ca", symbol: "DACKIE", coinGeckoId: "dackieswap", decimals: 18, price: 0.00655},
{chain: 34, addr: "0000000000000000000000005300000000000000000000000000000000000004", symbol: "WETH", coinGeckoId: "bridged-wrapped-ether-scroll", decimals: 18, price: 3145.98},
{chain: 34, addr: "000000000000000000000000f55bec9cafdbe8730f096aa55dad6d22d44099df", symbol: "USDT", coinGeckoId: "bridged-tether-scroll", decimals: 6, price: 1.00},
{chain: 34, addr: "00000000000000000000000006efdbff2a14a7c8e15944d1f4a48f9f95f663a4", symbol: "USDC", coinGeckoId: "bridged-usd-coin-scroll", decimals: 6, price: 1.00},
{chain: 34, addr: "000000000000000000000000eb466342c4d449bc9f53a865d5cb90586f405215", symbol: "AXLUSDC", coinGeckoId: "bridged-axelar-wrapped-usd-coin-scroll", decimals: 6, price: 1.01},
{chain: 34, addr: "0000000000000000000000003c1bca5a656e69edcd0d4e36bebb3fcdaca60cf1", symbol: "WBTC", coinGeckoId: "bridged-wrapped-bitcoin-scroll", decimals: 8, price: 64415.17},
{chain: 34, addr: "00000000000000000000000060d01ec2d5e98ac51c8b4cf84dfcce98d527c747", symbol: "IZI", coinGeckoId: "izumi-finance", decimals: 18, price: 0.0142},
{chain: 34, addr: "0000000000000000000000000a3bb08b3a15a19b4de82f8acfc862606fb69a2d", symbol: "IUSD", coinGeckoId: "izumi-bond-usd", decimals: 18, price: 0.9195},
{chain: 34, addr: "000000000000000000000000f610a9dfb7c89644979b4a0f27063e9e7d7cda32", symbol: "WSTETH", coinGeckoId: "bridged-wrapped-lido-staked-ether-scroll", decimals: 18, price: 3659.28},
{chain: 34, addr: "000000000000000000000000cA77eB3fEFe3725Dc33bccB54eDEFc3D9f764f97", symbol: "DAI", coinGeckoId: "dai", decimals: 18, price: 1.00},
{chain: 34, addr: "00000000000000000000000053878B874283351D26d206FA512aEcE1Bef6C0dD", symbol: "RETH", coinGeckoId: "rocket-pool-eth", decimals: 18, price: 3475.55},
}
}

View File

@ -147,7 +147,7 @@ func GuardianOptionAccountant(
}
if websocket == "" {
return errors.New("if accountantContract is specified, accountantWS is required")
return errors.New("if either accountantContract or accountantNttContract is specified, accountantWS is required")
}
if contract != "" {
if wormchainConn == nil {