Skip to content

Commit

Permalink
feat: bash scripts to deploy, generate allocs genesis file, and check it
Browse files Browse the repository at this point in the history
  • Loading branch information
anna-carroll committed Aug 30, 2024
1 parent 75db01b commit 6dcf792
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 0 deletions.
59 changes: 59 additions & 0 deletions allocs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
## Allocs

These scripts are utilities for setting up the `genesis.json` file for a new chain.

Developers write Forge script(s) that deploy and configure the contracts they wish to be pre-deployed on their chain. These scripts can then produce an `alloc` JSON file to input to `genesis.json`, which will setup those contracts with the correct code and storage slots.

## Usage

### Dependencies

Install `heimdall` - instructions [here](https://github.com/Jon-Becker/heimdall-rs/tree/main?tab=readme-ov-file#installation--usage)

Install `foundry` - instructions [here](https://book.getfoundry.sh/getting-started/installation)

### Setup Scripts

First, the developer must setup their `deploy-scripts.json` with the Forge scripts they want to run.

Each script is represented in JSON with the following fields:
- `relativePath`: the relative path to the repo containing the Forge script to run.
- `deployFile`: the file name that contains the Forge script.
- `deployContract`: the name of the contract in which the script is defined.
- `deploySignature`: the function signature of the deploy script

Using Uniswap's [Permit2](https://github.com/Uniswap/permit2/blob/main/script/DeployPermit2.s.sol) as an example, the JSON would look like this:
```
{
"relativePath": "../permit2",
"deployFile": "DeployPermit2.s.sol",
"deployContract": "DeployPermit2",
"deploySignature": "run"
}
```

### Deploy

This bash script will run each of the deploy scripts within their respective repos, then output the addresses of every contract deployed:

```shell
$ ./allocs/deploy.sh $RPC_URL $PRIVATE_KEY
```

### Generate Alloc

This script will read from the outputs generated by the deploy script, then use `cast code` and `heimdall dump` to generate a complete `alloc` JSON:

```shell
$ ./allocs/generate-alloc.sh $ARCHIVE_RPC_URL
```

NOTE: You MUST provide an archive RPC endpoint that supports `trace_replayBlockTransactions`, as `heimdall dump` relies on this endpoint. Unfortuntately, at the time of writing, `anvil` does not support this endpoint.

### Check Alloc

If you have an `alloc` JSON and you wish to check the storage slots against a deployed chain, you can run the following script:
```shell
$ ./allocs/check-alloc.sh $RPC_URL
```
Note that a non-archive RPC endpoint is fine for this command.
30 changes: 30 additions & 0 deletions allocs/check-alloc.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# ./allocs/check-alloc.sh $RPC_URL

rpc=$1
chainid=$(cast chain-id --rpc-url $rpc)

# Pull the current alloc JSON
contents=$(cat allocs/$chainid/alloc.json)

# Get all addresses JSON
addrs=$(echo $contents | jq -r '.alloc | keys[]')

# For each contract,
for addr in $addrs; do
# Get the code using `cast`
code=$(cast code $addr --rpc-url $rpc)
# replace the value in the JSON with the queried code
contents=$(echo $contents | jq --arg addy "$addr" --arg newCode "$code" '.alloc[$addy].code = $newCode')

# Get the storage slots in the JSON
slots=$(echo $contents | jq -r --arg addy "$addr" '.alloc[$addy].storage | select(. != null) | keys[]')
for slot in $slots; do
# Get the storage value using `cast`
value=$(cast storage $addr $slot --rpc-url $rpc)
# replace the value in the JSON with the queried storage value
contents=$(echo $contents | jq --arg addy "$addr" --arg slot "$slot" --arg newValue "$value" '.alloc[$addy].storage[$slot] = $newValue')
done
done

echo "$contents" > ./allocs/$chainid/alloc.json
echo "Done - allocs re-written to alloc.json!"
30 changes: 30 additions & 0 deletions allocs/deploy-scripts.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[
{
"relativePath": "../permit2",
"deployFilePath": "script",
"deployFile": "DeployPermit2.s.sol",
"deployContract": "DeployPermit2",
"deploySignature": "run"
},
{
"relativePath": "../zenith",
"deployFilePath": "script",
"deployFile": "ZenithL2.s.sol",
"deployContract": "L2Script",
"deploySignature": "deploySystem"
},
{
"relativePath": "../zenith",
"deployFilePath": "script",
"deployFile": "DeployGnosisSafe.s.sol",
"deployContract": "GnosisScript",
"deploySignature": "deployGnosis"
},
{
"relativePath": "../stablecoin-evm",
"deployFilePath": "scripts/deploy",
"deployFile": "deploy-fiat-token.s.sol",
"deployContract": "DeployFiatToken",
"deploySignature": "run"
}
]
26 changes: 26 additions & 0 deletions allocs/deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# ./allocs/deploy.sh $RPC_URL $PRIVATE_KEY
# NOTE: before running, setup the forge scripts that will run at `allocs/deploy-scripts.json`

rpc=$1
privateKey=$2

# parse array of script commands `allocs/deploy-scripts.json``
scripts=$(cat allocs/deploy-scripts.json | jq -c '.[]')

echo "$scripts" | while IFS= read -r script; do
# pull the script vars
relativePath=$(echo "$script" | jq -r '.relativePath')
deployFilePath=$(echo "$script" | jq -r '.deployFilePath')
deployFile=$(echo "$script" | jq -r '.deployFile')
deployContract=$(echo "$script" | jq -r '.deployContract')
deploySignature=$(echo "$script" | jq -r '.deploySignature')

# cd to a new repo if necessary
cd $relativePath

# run the deploy script
forge script $deployFilePath/${deployFile}:${deployContract} --sig $deploySignature --rpc-url $rpc --private-key $privateKey --broadcast
done

# write the addresses
./allocs/write-output.sh $rpc
36 changes: 36 additions & 0 deletions allocs/generate-alloc.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# ./allocs/generate.sh $ARCHIVE_RPC_URL

rpc=$1
chainid=$(cast chain-id --rpc-url $rpc)

# set empty allocs
alloc="{}"

# parse the JSON at `addresses.json` and get an array of addresses
addresses=$(cat allocs/$chainid/addresses.json | jq -r '.[] | .contractAddress')
fromBlock=$(printf "%d\n" $(cat allocs/$chainid/blocks.json | jq -r 'sort | .[0]'))
toBlock=$(printf "%d\n" $(cat allocs/$chainid/blocks.json | jq -r 'sort | .[-1]'))

# loop through addresses,
for addr in $addresses; do
# CODE
# Get the code using `cast`
code=$(cast code $addr --rpc-url $rpc --block $toBlock)
# replace the value in the JSON with the queried code
alloc=$(echo $alloc | jq --arg addy "$addr" --arg newCode "$code" '.alloc[$addy].code = $newCode')

# STORAGE
# Get the storage slots using heimdall
echo "Dumping storage for $addr..."
heimdall dump $addr --from-block $fromBlock --to-block $toBlock --rpc-url $rpc --output ./allocs/$chainid/$addr
# parse the .csv output to json
storage=$(awk -F, 'NR>1 {printf "\"%s\": \"%s\", ", $1, $2}' ./allocs/$chainid/$addr/dump.csv | sed 's/, $//')
# replace the value in the JSON with the queried storage values
alloc=$(echo $alloc | jq --arg addy "$addr" --argjson storage "{$storage}" '.alloc[$addy].storage = $storage')
# remove the .csv files
rm -rf ./allocs/$chainid/$addr/
done

touch ./allocs/$chainid/alloc.json
echo "$alloc" | jq '.' > ./allocs/$chainid/alloc.json
echo "Done - generated allocs written to ./allocs/$chainid/alloc.json!"
43 changes: 43 additions & 0 deletions allocs/write-output.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# ./allocs/write-addresses.sh $RPC_URL
# NOTE: before running, setup the forge scripts to inspect outputs from at `allocs/deploy-scripts.json`

rpc=$1
chainid=$(cast chain-id --rpc-url $rpc)

contracts="[]"
blocks="[]"

workingdir=$(pwd)
mkdir -p ./allocs/$chainid

# parse array of script commands `allocs/deploy-scripts.json``
scripts=$(cat allocs/deploy-scripts.json | jq -c '.[]')

echo "$scripts" | while IFS= read -r script; do
# pull the script vars
relativePath=$(echo "$script" | jq -r '.relativePath')
deployFile=$(echo "$script" | jq -r '.deployFile')
deployContract=$(echo "$script" | jq -r '.deployContract')
deploySignature=$(echo "$script" | jq -r '.deploySignature')

# cd to the script repo
cd $relativePath

# get contracts deployed via CREATE or CREATE2
newContracts=$(cat broadcast/${deployFile}/${chainid}/${deploySignature}-latest.json | jq '[.transactions[] | select(.transactionType == ("CREATE", "CREATE2")) | {contractName, contractAddress}]')
# get contracts deployed in sub-calls
additionalContracts=$(cat broadcast/${deployFile}/${chainid}/${deploySignature}-latest.json | jq '[.transactions[].additionalContracts[] | {contractAddress: .address}]')
# append all new contracts to the running total
contracts=$(echo "$contracts" "$newContracts" "$additionalContracts" | jq -s '.[0] + .[1] + .[2]')
# write addresses to file
echo "$contracts" > $workingdir/allocs/$chainid/addresses.json

# get blocks
newBlocks=$(cat broadcast/${deployFile}/${chainid}/${deploySignature}-latest.json | jq '[.receipts[].blockNumber]')
# append new blocks to the running total
blocks=$(echo "$blocks" "$newBlocks" | jq -s '.[0] + .[1] | sort | unique')
# write blocks to file
echo "$blocks" > $workingdir/allocs/$chainid/blocks.json
done

echo "Done! Outputs written to ./allocs/$chainid/"

0 comments on commit 6dcf792

Please sign in to comment.