Skip to content

Commit 6dcf792

Browse files
committed
feat: bash scripts to deploy, generate allocs genesis file, and check it
1 parent 75db01b commit 6dcf792

File tree

6 files changed

+224
-0
lines changed

6 files changed

+224
-0
lines changed

allocs/README.md

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
## Allocs
2+
3+
These scripts are utilities for setting up the `genesis.json` file for a new chain.
4+
5+
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.
6+
7+
## Usage
8+
9+
### Dependencies
10+
11+
Install `heimdall` - instructions [here](https://github.com/Jon-Becker/heimdall-rs/tree/main?tab=readme-ov-file#installation--usage)
12+
13+
Install `foundry` - instructions [here](https://book.getfoundry.sh/getting-started/installation)
14+
15+
### Setup Scripts
16+
17+
First, the developer must setup their `deploy-scripts.json` with the Forge scripts they want to run.
18+
19+
Each script is represented in JSON with the following fields:
20+
- `relativePath`: the relative path to the repo containing the Forge script to run.
21+
- `deployFile`: the file name that contains the Forge script.
22+
- `deployContract`: the name of the contract in which the script is defined.
23+
- `deploySignature`: the function signature of the deploy script
24+
25+
Using Uniswap's [Permit2](https://github.com/Uniswap/permit2/blob/main/script/DeployPermit2.s.sol) as an example, the JSON would look like this:
26+
```
27+
{
28+
"relativePath": "../permit2",
29+
"deployFile": "DeployPermit2.s.sol",
30+
"deployContract": "DeployPermit2",
31+
"deploySignature": "run"
32+
}
33+
```
34+
35+
### Deploy
36+
37+
This bash script will run each of the deploy scripts within their respective repos, then output the addresses of every contract deployed:
38+
39+
```shell
40+
$ ./allocs/deploy.sh $RPC_URL $PRIVATE_KEY
41+
```
42+
43+
### Generate Alloc
44+
45+
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:
46+
47+
```shell
48+
$ ./allocs/generate-alloc.sh $ARCHIVE_RPC_URL
49+
```
50+
51+
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.
52+
53+
### Check Alloc
54+
55+
If you have an `alloc` JSON and you wish to check the storage slots against a deployed chain, you can run the following script:
56+
```shell
57+
$ ./allocs/check-alloc.sh $RPC_URL
58+
```
59+
Note that a non-archive RPC endpoint is fine for this command.

allocs/check-alloc.sh

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# ./allocs/check-alloc.sh $RPC_URL
2+
3+
rpc=$1
4+
chainid=$(cast chain-id --rpc-url $rpc)
5+
6+
# Pull the current alloc JSON
7+
contents=$(cat allocs/$chainid/alloc.json)
8+
9+
# Get all addresses JSON
10+
addrs=$(echo $contents | jq -r '.alloc | keys[]')
11+
12+
# For each contract,
13+
for addr in $addrs; do
14+
# Get the code using `cast`
15+
code=$(cast code $addr --rpc-url $rpc)
16+
# replace the value in the JSON with the queried code
17+
contents=$(echo $contents | jq --arg addy "$addr" --arg newCode "$code" '.alloc[$addy].code = $newCode')
18+
19+
# Get the storage slots in the JSON
20+
slots=$(echo $contents | jq -r --arg addy "$addr" '.alloc[$addy].storage | select(. != null) | keys[]')
21+
for slot in $slots; do
22+
# Get the storage value using `cast`
23+
value=$(cast storage $addr $slot --rpc-url $rpc)
24+
# replace the value in the JSON with the queried storage value
25+
contents=$(echo $contents | jq --arg addy "$addr" --arg slot "$slot" --arg newValue "$value" '.alloc[$addy].storage[$slot] = $newValue')
26+
done
27+
done
28+
29+
echo "$contents" > ./allocs/$chainid/alloc.json
30+
echo "Done - allocs re-written to alloc.json!"

allocs/deploy-scripts.json

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
[
2+
{
3+
"relativePath": "../permit2",
4+
"deployFilePath": "script",
5+
"deployFile": "DeployPermit2.s.sol",
6+
"deployContract": "DeployPermit2",
7+
"deploySignature": "run"
8+
},
9+
{
10+
"relativePath": "../zenith",
11+
"deployFilePath": "script",
12+
"deployFile": "ZenithL2.s.sol",
13+
"deployContract": "L2Script",
14+
"deploySignature": "deploySystem"
15+
},
16+
{
17+
"relativePath": "../zenith",
18+
"deployFilePath": "script",
19+
"deployFile": "DeployGnosisSafe.s.sol",
20+
"deployContract": "GnosisScript",
21+
"deploySignature": "deployGnosis"
22+
},
23+
{
24+
"relativePath": "../stablecoin-evm",
25+
"deployFilePath": "scripts/deploy",
26+
"deployFile": "deploy-fiat-token.s.sol",
27+
"deployContract": "DeployFiatToken",
28+
"deploySignature": "run"
29+
}
30+
]

allocs/deploy.sh

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# ./allocs/deploy.sh $RPC_URL $PRIVATE_KEY
2+
# NOTE: before running, setup the forge scripts that will run at `allocs/deploy-scripts.json`
3+
4+
rpc=$1
5+
privateKey=$2
6+
7+
# parse array of script commands `allocs/deploy-scripts.json``
8+
scripts=$(cat allocs/deploy-scripts.json | jq -c '.[]')
9+
10+
echo "$scripts" | while IFS= read -r script; do
11+
# pull the script vars
12+
relativePath=$(echo "$script" | jq -r '.relativePath')
13+
deployFilePath=$(echo "$script" | jq -r '.deployFilePath')
14+
deployFile=$(echo "$script" | jq -r '.deployFile')
15+
deployContract=$(echo "$script" | jq -r '.deployContract')
16+
deploySignature=$(echo "$script" | jq -r '.deploySignature')
17+
18+
# cd to a new repo if necessary
19+
cd $relativePath
20+
21+
# run the deploy script
22+
forge script $deployFilePath/${deployFile}:${deployContract} --sig $deploySignature --rpc-url $rpc --private-key $privateKey --broadcast
23+
done
24+
25+
# write the addresses
26+
./allocs/write-output.sh $rpc

allocs/generate-alloc.sh

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# ./allocs/generate.sh $ARCHIVE_RPC_URL
2+
3+
rpc=$1
4+
chainid=$(cast chain-id --rpc-url $rpc)
5+
6+
# set empty allocs
7+
alloc="{}"
8+
9+
# parse the JSON at `addresses.json` and get an array of addresses
10+
addresses=$(cat allocs/$chainid/addresses.json | jq -r '.[] | .contractAddress')
11+
fromBlock=$(printf "%d\n" $(cat allocs/$chainid/blocks.json | jq -r 'sort | .[0]'))
12+
toBlock=$(printf "%d\n" $(cat allocs/$chainid/blocks.json | jq -r 'sort | .[-1]'))
13+
14+
# loop through addresses,
15+
for addr in $addresses; do
16+
# CODE
17+
# Get the code using `cast`
18+
code=$(cast code $addr --rpc-url $rpc --block $toBlock)
19+
# replace the value in the JSON with the queried code
20+
alloc=$(echo $alloc | jq --arg addy "$addr" --arg newCode "$code" '.alloc[$addy].code = $newCode')
21+
22+
# STORAGE
23+
# Get the storage slots using heimdall
24+
echo "Dumping storage for $addr..."
25+
heimdall dump $addr --from-block $fromBlock --to-block $toBlock --rpc-url $rpc --output ./allocs/$chainid/$addr
26+
# parse the .csv output to json
27+
storage=$(awk -F, 'NR>1 {printf "\"%s\": \"%s\", ", $1, $2}' ./allocs/$chainid/$addr/dump.csv | sed 's/, $//')
28+
# replace the value in the JSON with the queried storage values
29+
alloc=$(echo $alloc | jq --arg addy "$addr" --argjson storage "{$storage}" '.alloc[$addy].storage = $storage')
30+
# remove the .csv files
31+
rm -rf ./allocs/$chainid/$addr/
32+
done
33+
34+
touch ./allocs/$chainid/alloc.json
35+
echo "$alloc" | jq '.' > ./allocs/$chainid/alloc.json
36+
echo "Done - generated allocs written to ./allocs/$chainid/alloc.json!"

allocs/write-output.sh

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# ./allocs/write-addresses.sh $RPC_URL
2+
# NOTE: before running, setup the forge scripts to inspect outputs from at `allocs/deploy-scripts.json`
3+
4+
rpc=$1
5+
chainid=$(cast chain-id --rpc-url $rpc)
6+
7+
contracts="[]"
8+
blocks="[]"
9+
10+
workingdir=$(pwd)
11+
mkdir -p ./allocs/$chainid
12+
13+
# parse array of script commands `allocs/deploy-scripts.json``
14+
scripts=$(cat allocs/deploy-scripts.json | jq -c '.[]')
15+
16+
echo "$scripts" | while IFS= read -r script; do
17+
# pull the script vars
18+
relativePath=$(echo "$script" | jq -r '.relativePath')
19+
deployFile=$(echo "$script" | jq -r '.deployFile')
20+
deployContract=$(echo "$script" | jq -r '.deployContract')
21+
deploySignature=$(echo "$script" | jq -r '.deploySignature')
22+
23+
# cd to the script repo
24+
cd $relativePath
25+
26+
# get contracts deployed via CREATE or CREATE2
27+
newContracts=$(cat broadcast/${deployFile}/${chainid}/${deploySignature}-latest.json | jq '[.transactions[] | select(.transactionType == ("CREATE", "CREATE2")) | {contractName, contractAddress}]')
28+
# get contracts deployed in sub-calls
29+
additionalContracts=$(cat broadcast/${deployFile}/${chainid}/${deploySignature}-latest.json | jq '[.transactions[].additionalContracts[] | {contractAddress: .address}]')
30+
# append all new contracts to the running total
31+
contracts=$(echo "$contracts" "$newContracts" "$additionalContracts" | jq -s '.[0] + .[1] + .[2]')
32+
# write addresses to file
33+
echo "$contracts" > $workingdir/allocs/$chainid/addresses.json
34+
35+
# get blocks
36+
newBlocks=$(cat broadcast/${deployFile}/${chainid}/${deploySignature}-latest.json | jq '[.receipts[].blockNumber]')
37+
# append new blocks to the running total
38+
blocks=$(echo "$blocks" "$newBlocks" | jq -s '.[0] + .[1] | sort | unique')
39+
# write blocks to file
40+
echo "$blocks" > $workingdir/allocs/$chainid/blocks.json
41+
done
42+
43+
echo "Done! Outputs written to ./allocs/$chainid/"

0 commit comments

Comments
 (0)