diff --git a/.github/workflows/bridge-docker.yml b/.github/workflows/bridge-docker.yml new file mode 100644 index 0000000..f44be0c --- /dev/null +++ b/.github/workflows/bridge-docker.yml @@ -0,0 +1,72 @@ +name: Build Bridge Docker Image + +on: + push: + branches: + - main + - dev + pull_request: + branches: + - main + - dev + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }}/bridge + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=sha,prefix= + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + file: ./scripts/Dockerfile + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Test Docker image + run: | + docker build -t bridge-test -f scripts/Dockerfile . + # Test that the image has the required tools + docker run --rm bridge-test which forge + docker run --rm bridge-test which cast + docker run --rm bridge-test which jq + # Test that contracts are built + docker run --rm --entrypoint /bin/bash bridge-test -c "cd /app/contracts && forge build --sizes" || true + echo "Docker image built and tested successfully!" diff --git a/.gitignore b/.gitignore index 626e86d..56cc852 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ out/ !/broadcast /broadcast/*/31337/ /broadcast/**/dry-run/ +contracts/broadcast/ +contracts/artifacts/ # Docs docs/ diff --git a/contracts/artifacts/l1-deploy.json b/contracts/artifacts/l1-deploy.json deleted file mode 100644 index 77ae8be..0000000 --- a/contracts/artifacts/l1-deploy.json +++ /dev/null @@ -1 +0,0 @@ -{"middlewareShim":"0xf6760b282239d1da158E5e7ac46e4472B096e1A4","stateRetriever":"0x6521f81EF1945e14997E16167A7F462df8a82913"} \ No newline at end of file diff --git a/contracts/artifacts/l2-deploy.json b/contracts/artifacts/l2-deploy.json deleted file mode 100644 index f540802..0000000 --- a/contracts/artifacts/l2-deploy.json +++ /dev/null @@ -1 +0,0 @@ -{"blsSignatureChecker":"0x08D2637AaA825629CD0C7631E80c75b3FbEA1b17","registryCoordinatorMimic":"0x16313cadeef9Df284C57b6325d8b55DdaE655695","signatureConsumer":"0x8bdB33CDcd019848fde26Ab8f54D82263284ddbB"} \ No newline at end of file diff --git a/contracts/artifacts/middlewareDataProof.json b/contracts/artifacts/middlewareDataProof.json deleted file mode 100644 index fe0083b..0000000 --- a/contracts/artifacts/middlewareDataProof.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "middlewareBlockNumber": "3924211", - "slotNumber": "1234", - "storageHash": "0x2ba7e17d37ab6bbfc7a9e1cb4f52971f18786dfc3fa683afc05e7931f23aae9f", - "executionStateRoot": "0xfc028d620d7953b77dd761c3af6b6be0bb16e3661770df5d209659cbedc52182", - "storageProof": [ - "0xf8718080a036aae9581bb7a21b62fb12221b7e7c484902885c884273a97c5d89a05196bdff80a02df56569271f40a2bbff19749f44a5f0a67f1e1d27bb68704d5432c1754f8b9f808080808080a05b6c188cc3e3f28af879b0260a7d96cf4d2ef6c12042d45130d13b80cadf0ed88080808080", - "0xf843a0390decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563a1a02ad1496574130c3bbd1ccb4cbd759726e30684da2b7fc4e09abb8494ea51035b" - ], - "accountProof": [ - "0xf90211a09d9248de748f3f0f8ef7b7abcd55f5ddf32241ab793f0bfaca97e8abed7bdb1ba08aba8517791eadaa2cc554c6ff356d4152e9420a44f8d37a25bcac63374ff290a07eb3bdab3d167489ab694ef93594244b68874431a5c62d9fab54c743141cd410a02f9e4db75f208672045b35c8a7655852f1f90ee4153627b77792bbf9b5926541a0a95748a7ace02a9d2134844ab9b4a4706eb8cb5774e9e3e62f910107a5f81d1fa04c69424c107878d57dd504b1aca5a73b0171b984f8193cbfb5a986f28b562288a048677b758145cf7f6e52fbd15ee60f294c479397839f5e0c86bb5e38938e79f3a0680520f61ad8bdfe87ddb6f78e171042aeedb76cd05809d999652d1f7c365b45a0acab4d4334dd8fff6ea673f660f0510b777811032f1295df6fbdc25928856756a0b325432006bdcd03af710c1280e002a019af2d1e7fd33ac62ddc65a735933852a063cbbd84ee0e9ecb1969aeee6d252f4848a79af614496f462293075301011041a0c23adf4314ff6d49888bac78088e589bb8ae1453bce692d587e1a15d13f7511ba08441fa4fec3529e6fafd15afb151e530efc8ba913869633392209335d6ca1d97a05d83d08dfe49a0c0d420c929a7381c75fdd0e89a0e5f399e04789787c6141aa6a0ffd8d3a3d9079babf6afcb955657a52dd9caf03e8c9f6e4c91fddd016263356ca0e718f79acb5f5b60a33f307a30afe0432f058907ac86d91bbfd2973f82cf1eeb80", - "0xf90211a041c2c6a15915cb244e0d1aaef49c4371495779b12b2803c676367a42337871b1a0b1814cbfb70af3d7cb3518dc8f85f2eb30563e29c8bcb4022f6ff013e06ddf9ea0c1dd7e66617710a3b376259d8287c5fe309053c9ddfc286b3afde3249be51099a0d0cac8c60c88e3bb7c5ef98f01dc33a31e5a6cdb96feef05a6c5f8288f524f26a047b76db97c2ea149b4446eef2dd4ef44e541318f6d6cc06f62cd1569c670c117a092a59e0bdbaec747106c9f029ccde9f119a38517206e14df5f1ecfa1ae38bc9aa06483e784a27428f6bb263470c8360f028c102db5b90120f923c739b504b53738a08bc7c4cf06c436b11a73dc5c3dd0c14c5fadb3ac4620616d817155b9771ed489a06724e3a84d6f764cd7fbb644b4bde0c7578fc61307f91361f98cda3aaea4f2f1a036d104b6fad7d01e443938f22c3eb3611a88434d7e0b1991d9f292ae92aa37c3a0dcce0cac77841472c18ed9aae9c469dac7153f40902abaf9aae85c07c7f39d85a05b0df95e27bd10604caeee0c237be64de9a54363340864a303e214d1d069d206a0aabcb4b43478064ceb2acba0c0cdf1b9d3e4014b9f8b8478ec9ea232840e2035a08eeb7f4e8fa5a33718838291be7c9f25a44b432947089be476e3d5a8c558746ca094b2ebb4632ad35ec18f6c32dc018988bcb0897de3c267f875b4ccb23d247ec7a0ab54ad472b173d8e826979cba71e7e6673918f476846a4d0857b5e7d30870c6980", - "0xf90211a070dc7c44e07fb22d29d3f64de6c8ff5a6d0c825fe1952a8e90540d86e9a2f24da055bca8d80de6aecff52e6faa76e6b62899001587592723fc053a846ac7d2c14ca012280ac67ba79fc39a39070794329e0f6915b68a40e1a5a12e5ba1feffe2198ca025fae8d7b204222ac3f124fbe1f6cdd5d2ecf8804f955468d0d336afa293777aa006ef871d83368da9fc6d9da8454cd41a29338edcd51ea593ffed76dcab532181a0146b937770154f697a0a7ed6ce8c13af4c1c17cdc3eacddd14f6a9b7f86f422da0dbc1d3de741733e16a15b117b0d096e8248d7ffa5ba793552969355340631655a078399644a9db1cf8edac27002792db84a95fe06d4d6a015fec7694e6a7d38e4ba01b2e27a64d102acaf01720d384afa92c0f31b7ef1a65142c8e920b7c234c1a07a0974e7115f9a5f03edacd0f480ea4c13c1e50f38b134cc53215e74fb03c4fdf21a069aa38a93b9c500bb929adf8c6ff1cf23613ec99e470786e84e9f4d8bf64bef5a098302484cd290fcb4cf7958e8c5e1945e6a7848ae12b332b1b7a6494e6b493c5a021b69042c10bdd6526bc174cc59a7176b3647c125c663bb63f40e7b8f9150622a02c7b7a8cfede4ac71f84d11ac7cdf2fcba5c65beb64b90d8734a6b86389a635aa04e57768fdd2d42eba45793e0a49c91831d0ec0fa9d80b0a46ce614c4328dafc6a09655dc3ac3e8f17f2df3f48627007c07fd624428ad3aa0b6632111f17237c2f680", - "0xf90211a0118657a72e5af93d990b05f1931aa6a92289209d522fd7a28dfff641e22d8ff6a0db38c66cc488fa205be0ce9196e9d93171d0e422038044e0c66f3a0c2359ee69a01853fcf10d61fde835b165b86ed825949a431cbdbbf70ebc8c2d509169017da0a0b6a492bef3f4cee68b96ff4f9d39d83e937d09fd17642a3bfd2b14397a1dba7fa0bad6bd0ca669f3792cdf8de48fa58145f6f1e22ff92be08a7000697d08909e1ca0a723f29b80eba9137a9b62f7cea2a739861374e47df8942f96ed0d34c4531d44a0f8b2f045031d17e682a83ca53b7c69b6a36b4cc6ee5eacee749f77dfc6536991a0fb46cb44f62f829c08ad2b6122af78a2061932bc0a0d4f3286e5e4ec4ace28ffa0aa90093d783f47d77733d4d3e3bd83b899d403a22659b4bc1b407224f8ba59a2a0ef90d3156007524bdcc8b12d0729a776e5ed536281abab519210b1280ed01783a05b3b6707b1959f6e6087d90cab52ea233666cbe551468c7cf5c05bb192f1a978a0b912f8a9788b4478dcb4864484e60669325df9d6ef85988db77e6d09d3e734fba0148a2045524eeb67195a6e1e8d8b2d940ee612a9cbaa6f75ed0662b7d7ae936fa09491b3fc4840ae763716fa3aa4781242de5cb093577b1e3cc72d0fc454eb42dea0efe1bffd27130567c8abc8b80511587ab6c3ae1f90e990ce332287d035f02bb9a0e82a9ef135547a7e5cff4f6f9ff56e0a446af4f16fc514b8479f630caed75b4880", - "0xf90211a0e719fd250806813cf844fe753ad062acd7016514c75d4422f8ca82a2759d87cea0e662e8b1418d5d1cd6c21a70ad723ad2b0e1ccdea305236c9477ba0ec400ce28a00306f7bc8c02109420347dc9deb0ef7b79262b4b949ddf3c236c4dd0c587a0c2a030c5b2d2f904bd0626f67d7dfbb2b0b9509660a9d0802c0158f11320575f00fda058a2b795216eb43470fd06fa97da2db81de06b0063a78d96f45e6715ae2243eba0edfe731ba6616314368703ffba8822efe713ec0cd116a0043c4cd1bd286d42d0a0b4370c6e7835ad3267e7f7814aaf68b0843bfeed0f39e6030e4a3474e34540f8a0e4b4d5ed18edb676d9e1185df94e7caee34bf871047eb5d2b7d0d29e252aa4bea0847407deaf6fa0b36966b41a96c4a47c839042dd3dc630390d2305803e5e18f3a0bd40195f57ce9b1dd45639c8ec2d34ace13fe12f6a7fcafb011194cc01d1f032a0a923c2b1ee4c11d9f7ecfd5e23977e6c21bc1e432236d445e04cdd931d73d191a0a6af769c5a6734379f60218173ef3aeebabe480f1cade1a491bf7da9beab09eca0d8465936d4df1ef1039fe9f916a5e5645257c0673d2dcd29149e5fce28e0590ea07a36b155fa0ee0aad9640eed6e7ec1e0436bfea27634c79594dcd7311799eda3a0e36ca43b45d8ebf5af57ce3ce53ae6bf7025a5ae8bb5ae5e73e4f5629fe7138da0190f9acff67008017acc0caf417c88bf57a6f1052ba980a0a4f929f222769bf480", - "0xf90211a0a4608062b64dc79d2c97e98bc513d980c108bb897124dcb30273353e426bc084a02d6975511e645fe697249f550c01c49167028570c269f91d160cfdb714de6beda0dd65a7336295d49e6edbaf7a4545b3097ce18f00ae3e39572da8c5c43ca071c2a0278ab3782032185c9c63c9c92b6495fbf06508c40531557830cade26482a7f61a0878f976bedaa375d7de3929b4da7420d936028489e9c9cccbb59dd84d5391d59a014e1d438a573d45fbd817a4c0418c157a12e7ba288b26b6df5f9c7fe833fb7c4a0a76d71f868facbdc08734e84b870da7c681aed3a911fa4f0e7c1386f29f9bb37a0a62f5cdab28babf6d9ce39f0c9ba2b2b4316bdeee3f2ea8a2185d32983a9d2d7a0ff52f540fb42a03f82c619c60b2c54fc13d4fbc1c963e876208c0c7b29134303a0f2a314b7b45b99e7a7c1877566efd963e4cd79948e713a74172d5dd1848ff102a0c3a37c08583d822cb46e0cc32a3bc98792715c188abee1fbc05e6962427fde62a054345b2a3a5c104171fc754abf3f00703776f6d6fe9f9f31a00c262f146e529aa025cf6bb916d7b10b9673a27298942b2944e00cbeba408eed0580253aae08693aa058053926194a246eb5d5ad786fe4919cf3bdd36f42b2fa14a22abcccb7fc09bea064ecc2b17a0a28a5bd28d40c083ac49c0f4c720729d8de56c128ed474f56cd49a065fb6df0cca77bce5d50b3e6ab7b2ff2ffeeafecd6020ef2a5ad8df26d6ff37580", - "0xf8f1a074447df526e583ec6bba467879678d0b4ae1c01adec7bf3148de4a593291f79080808080a0887b0355035aaa492985b7d3ac6d62340a3283a3fcb5bd913a78e60f873cded2a0e597bddc7c42f8d4dc3d3a420ac247a6472aa4b687253fea1e8e753de61e75cca0679bc197637d6bef0747155ae16308d90a69fce0e770348271a391df0ff8325580a0866e96d33b9516d6e2341e9f49c8d0ebd8720b5b9d1283e9e254aa0151c53b8b8080a0b79a067f48b8e5592a2908df13ee28bdcd3e96b7de8bc30e64a717868003f73b8080a0bbae10bc77c920b4c6aadace9925c4da855c2db0948cb532bef62649424137c280", - "0xf871a0d723cf3a2f0ced00fa503c2cc5baa0173086a476d8591f862882bc78b83068b3808080808080a0e9e75ff41d9d86341d4868e3b4d1395d7171b3eac54e150492f8cccfce0530fa8080a07943e748d9dcf9232cc185999b1744eadbb7fbdce3b03597cfa74197941c4700808080808080", - "0xf8669d2002b977b5132d6ed0f2d80cf1a13fc92a66ab036c24c9cfc345c55042b846f8440180a02ba7e17d37ab6bbfc7a9e1cb4f52971f18786dfc3fa683afc05e7931f23aae9fa0db35341074043b74d8c42641eab8fc4eb496db0e5931a24b0ab9b7cce6dcec09" - ] -} diff --git a/e2e/envs/bls-testnet.example.env b/e2e/envs/bls-testnet.example.env index de16e51..aa665b1 100644 --- a/e2e/envs/bls-testnet.example.env +++ b/e2e/envs/bls-testnet.example.env @@ -7,14 +7,24 @@ # BLS_SIGNATURE_CHECKER_ADDRESS=0xb7ba8bbc36AA5684fC44D02aD666dF8E23BEEbF8 # OPERATOR_STATE_RETRIEVER_ADDRESS=0xD5D7fB4647cE79740E6e83819EFDf43fa74F8C31 -# Holesky -DELEGATION_MANAGER_ADDRESS=0xA44151489861Fe9e3055d95adC98FbD462B948e7 -STRATEGY_MANAGER_ADDRESS=0xdfB5f6CE42aAA7830E94ECFCcAd411beF4d4D5b6 -LST_CONTRACT_ADDRESS=0x3F1c547b21f65e10480dE3ad8E19fAAC46C95034 -LST_STRATEGY_ADDRESS=0x7D704507b76571a51d9caE8AdDAbBFd0ba0e63d3 -REGISTRY_COORDINATOR_ADDRESS=0x3e43AA225b5cB026C5E8a53f62572b10D526a50B -BLS_SIGNATURE_CHECKER_ADDRESS=0xca249215e082e17c12bb3c4881839a3f883e5c6b -OPERATOR_STATE_RETRIEVER_ADDRESS=0xB4baAfee917fb4449f5ec64804217bccE9f46C67 +# Holesky +# DELEGATION_MANAGER_ADDRESS=0xA44151489861Fe9e3055d95adC98FbD462B948e7 +# STRATEGY_MANAGER_ADDRESS=0xdfB5f6CE42aAA7830E94ECFCcAd411beF4d4D5b6 +# LST_CONTRACT_ADDRESS=0x3F1c547b21f65e10480dE3ad8E19fAAC46C95034 +# LST_STRATEGY_ADDRESS=0x7D704507b76571a51d9caE8AdDAbBFd0ba0e63d3 +# REGISTRY_COORDINATOR_ADDRESS=0x3e43AA225b5cB026C5E8a53f62572b10D526a50B +# BLS_SIGNATURE_CHECKER_ADDRESS=0xca249215e082e17c12bb3c4881839a3f883e5c6b +# OPERATOR_STATE_RETRIEVER_ADDRESS=0xB4baAfee917fb4449f5ec64804217bccE9f46C67 + +# Sepolia +DELEGATION_MANAGER_ADDRESS=0xD4A7E1Bd8015057293f0D0A557088c286942e84b +STRATEGY_MANAGER_ADDRESS=0x2E3D6c0744b10eb0A4e6F679F71554a39Ec47a5D +LST_CONTRACT_ADDRESS=0x00c71b0fcadE911B2feeE9912DE4Fe19eB04ca56 +LST_STRATEGY_ADDRESS=0x8b29d91e67b013e855EaFe0ad704aC4Ab086a574 +ALLOCATION_MANAGER_ADDRESS=0x42583067658071247ec8CE0A516A58f682002d07 +REGISTRY_COORDINATOR_ADDRESS=0x3a8d838578a2459cc45c3f6459b2c2a50b725635 +BLS_SIGNATURE_CHECKER_ADDRESS=0x5f520a8517e74eb023b1c826b1b182ae39165a14 +OPERATOR_STATE_RETRIEVER_ADDRESS=0x471b515fb829c519abaa9278e944f5c6c43eff27 L1_FORK_URL= L2_FORK_URL= diff --git a/scripts/Dockerfile b/scripts/Dockerfile new file mode 100644 index 0000000..e403012 --- /dev/null +++ b/scripts/Dockerfile @@ -0,0 +1,31 @@ +# Bridge Script Docker Image +# Contains all dependencies to run bridge-to-l2.sh + +FROM ghcr.io/foundry-rs/foundry:latest + +# Install additional dependencies as root +USER root +RUN apt-get update && apt-get install -y --no-install-recommends \ + jq \ + curl \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Set working directory +WORKDIR /app + +# Copy contract sources and scripts +COPY contracts/foundry.toml contracts/foundry.toml +COPY contracts/src contracts/src +COPY contracts/script contracts/script +COPY contracts/lib contracts/lib +COPY scripts scripts + +# Contracts will be compiled on first run +WORKDIR /app + +# Make scripts executable +RUN chmod +x scripts/*.sh + +# Default entrypoint +ENTRYPOINT ["/app/scripts/bridge-to-l2.sh"] diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..4a4ce5b --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,60 @@ +# Bridge Scripts + +Scripts for bridging EigenLayer operator state from L1 to L2. + +## bridge-to-l2.sh + +Deploys bridge contracts and bridges operator state from an L1 registry coordinator to an L2 mimic contract using mock SP1Helios verification. + +### Prerequisites + +- [Foundry](https://book.getfoundry.sh/getting-started/installation) installed +- `cast` and `forge` available in PATH +- `jq` installed + +### Usage + +```bash +# Set required environment variables +export PRIVATE_KEY="0x..." +export L1_RPC_URL="https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY" +export L2_RPC_URL="https://gnosis-mainnet.g.alchemy.com/v2/YOUR_KEY" +export REGISTRY_COORDINATOR_ADDRESS="0x..." + +# Run the bridge script +./scripts/bridge-to-l2.sh +``` + +Or use an env file: + +```bash +cp scripts/bridge.env.example scripts/bridge.env +# Edit bridge.env with your values +source scripts/bridge.env && ./scripts/bridge-to-l2.sh +``` + +### What it does + +1. **Deploy L1 Contracts** - Deploys `MiddlewareShim` pointing to the registry coordinator +2. **Deploy L2 Contracts** - Deploys `SP1HeliosMock`, `RegistryCoordinatorMimic`, `BLSSignatureChecker` +3. **Update L1 Shim** - Calls `updateMiddlewareDataHash()` to snapshot operator state +4. **Generate Mock Proof** - Creates storage/account proofs and sets state root on mock +5. **Bridge State** - Runs `UpdateMimic.s.sol` to bridge state to L2 + +### Skip Deployment + +To use existing deployed contracts: + +```bash +export SKIP_DEPLOY=true +export L1_DEPLOY_FILE=/path/to/l1-deploy.json +export L2_DEPLOY_FILE=/path/to/l2-deploy.json +./scripts/bridge-to-l2.sh +``` + +### Output + +The script creates these files in `contracts/artifacts/`: +- `l1-deploy.json` - L1 contract addresses +- `l2-deploy.json` - L2 contract addresses +- `middlewareDataProof.json` - Generated storage proof diff --git a/scripts/bridge-to-l2.sh b/scripts/bridge-to-l2.sh new file mode 100755 index 0000000..2df350c --- /dev/null +++ b/scripts/bridge-to-l2.sh @@ -0,0 +1,276 @@ +#!/bin/bash + +####################################################################### +# Bridge EigenLayer Operator State from L1 to L2 +# +# This script deploys the bridge contracts and bridges operator state +# from an L1 registry coordinator to an L2 mimic contract. +# +# Required Environment Variables: +# PRIVATE_KEY - Private key for deployment and transactions +# L1_RPC_URL - RPC URL for L1 (e.g., Sepolia) +# L2_RPC_URL - RPC URL for L2 (e.g., Gnosis) +# REGISTRY_COORDINATOR_ADDRESS - L1 registry coordinator to bridge from +# +# Optional Environment Variables: +# SLOT_NUMBER - Slot number for mock proof (default: 12345) +# SKIP_DEPLOY - Set to "true" to skip deployment and use existing contracts +# L1_DEPLOY_FILE - Path to existing L1 deployment file (required if SKIP_DEPLOY=true) +# L2_DEPLOY_FILE - Path to existing L2 deployment file (required if SKIP_DEPLOY=true) +# +####################################################################### + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Validate required environment variables +validate_env() { + local missing=() + + [[ -z "$PRIVATE_KEY" ]] && missing+=("PRIVATE_KEY") + [[ -z "$L1_RPC_URL" ]] && missing+=("L1_RPC_URL") + [[ -z "$L2_RPC_URL" ]] && missing+=("L2_RPC_URL") + [[ -z "$REGISTRY_COORDINATOR_ADDRESS" ]] && missing+=("REGISTRY_COORDINATOR_ADDRESS") + + if [[ ${#missing[@]} -gt 0 ]]; then + log_error "Missing required environment variables:" + for var in "${missing[@]}"; do + echo " - $var" + done + exit 1 + fi +} + +# Get script directory and set paths +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONTRACTS_DIR="$(cd "$SCRIPT_DIR/../contracts" && pwd)" +ARTIFACTS_DIR="$CONTRACTS_DIR/artifacts" + +# Default values +SLOT_NUMBER="${SLOT_NUMBER:-12345}" +SKIP_DEPLOY="${SKIP_DEPLOY:-false}" + +# Validate environment +validate_env + +# Create artifacts directory +mkdir -p "$ARTIFACTS_DIR" + +# Set output paths +L1_OUT_PATH="${L1_DEPLOY_FILE:-$ARTIFACTS_DIR/l1-deploy.json}" +L2_OUT_PATH="${L2_DEPLOY_FILE:-$ARTIFACTS_DIR/l2-deploy.json}" +PROOF_FILE="$ARTIFACTS_DIR/middlewareDataProof.json" + +cd "$CONTRACTS_DIR" + +####################################################################### +# Step 1: Deploy L1 Contracts (MiddlewareShim) +####################################################################### + +if [[ "$SKIP_DEPLOY" != "true" ]]; then + log_info "Step 1: Deploying L1 contracts to $(echo $L1_RPC_URL | sed 's/\/.*//g')..." + + export REGISTRY_COORDINATOR_ADDRESS + export PRIVATE_KEY + export L1_OUT_PATH + + forge script script/e2e/DeployL1.s.sol:DeployL1 \ + --broadcast \ + --rpc-url "$L1_RPC_URL" \ + --quiet + + log_info "L1 contracts deployed. Output: $L1_OUT_PATH" +else + log_info "Step 1: Skipping L1 deployment (SKIP_DEPLOY=true)" + if [[ ! -f "$L1_OUT_PATH" ]]; then + log_error "L1 deployment file not found: $L1_OUT_PATH" + exit 1 + fi +fi + +# Read L1 deployment addresses +MIDDLEWARE_SHIM_ADDRESS=$(jq -r '.middlewareShim' "$L1_OUT_PATH") +log_info "MiddlewareShim: $MIDDLEWARE_SHIM_ADDRESS" + +####################################################################### +# Step 2: Deploy L2 Contracts (RegistryCoordinatorMimic) +####################################################################### + +if [[ "$SKIP_DEPLOY" != "true" ]]; then + log_info "Step 2: Deploying L2 contracts..." + + export MIDDLEWARE_SHIM_ADDRESS + export SP1HELIOS_ADDRESS="0x0000000000000000000000000000000000000000" + export IS_SP1HELIOS_MOCK="true" + export L2_OUT_PATH + + forge script script/e2e/DeployL2.s.sol:DeployL2 \ + --broadcast \ + --rpc-url "$L2_RPC_URL" \ + --quiet + + log_info "L2 contracts deployed. Output: $L2_OUT_PATH" +else + log_info "Step 2: Skipping L2 deployment (SKIP_DEPLOY=true)" + if [[ ! -f "$L2_OUT_PATH" ]]; then + log_error "L2 deployment file not found: $L2_OUT_PATH" + exit 1 + fi +fi + +# Read L2 deployment addresses +REGISTRY_COORDINATOR_MIMIC=$(jq -r '.registryCoordinatorMimic' "$L2_OUT_PATH") +BLS_SIGNATURE_CHECKER=$(jq -r '.blsSignatureChecker' "$L2_OUT_PATH") +log_info "RegistryCoordinatorMimic: $REGISTRY_COORDINATOR_MIMIC" +log_info "BLSSignatureChecker: $BLS_SIGNATURE_CHECKER" + +####################################################################### +# Step 3: Update L1 Shim (Snapshot operator state) +####################################################################### + +log_info "Step 3: Updating L1 MiddlewareShim (snapshotting operator state)..." + +TX_RESULT=$(cast send \ + --rpc-url "$L1_RPC_URL" \ + --private-key "$PRIVATE_KEY" \ + --json \ + "$MIDDLEWARE_SHIM_ADDRESS" \ + "updateMiddlewareDataHash()") + +TX_HASH=$(echo "$TX_RESULT" | jq -r '.transactionHash') +log_info "Transaction hash: $TX_HASH" + +# Wait for confirmation +sleep 3 + +BLOCK_NUMBER=$(cast receipt --rpc-url "$L1_RPC_URL" "$TX_HASH" --json | jq -r '.blockNumber') +log_info "Operator state snapshotted at block: $BLOCK_NUMBER" + +####################################################################### +# Step 4: Generate Mock Proof +####################################################################### + +log_info "Step 4: Generating mock proof..." + +# Get SP1Helios address from mimic +SP1HELIOS_ADDRESS=$(cast call "$REGISTRY_COORDINATOR_MIMIC" "LITE_CLIENT()(address)" --rpc-url "$L2_RPC_URL") +log_info "SP1Helios address: $SP1HELIOS_ADDRESS" + +# Get middleware block number +MIDDLEWARE_BLOCK_NUMBER=$(cast call "$MIDDLEWARE_SHIM_ADDRESS" "lastBlockNumber()" --rpc-url "$L1_RPC_URL" | cast to-dec) +log_info "Middleware block number: $MIDDLEWARE_BLOCK_NUMBER" + +# Get latest block and proof data +LATEST_BLOCK=$(cast block latest --rpc-url "$L1_RPC_URL" --json | jq -r '.number') +log_info "Latest L1 block: $LATEST_BLOCK" + +# Get storage proof for slot 0 (middlewareDataHash) +STORAGE_SLOT=0 +PROOF_DATA=$(cast proof -B "$LATEST_BLOCK" "$MIDDLEWARE_SHIM_ADDRESS" "$STORAGE_SLOT" --json --rpc-url "$L1_RPC_URL") + +# Get execution state root +EXECUTION_STATE_ROOT=$(cast block "$LATEST_BLOCK" --rpc-url "$L1_RPC_URL" --json | jq -r '.stateRoot') +log_info "Execution state root: $EXECUTION_STATE_ROOT" + +# Set execution state root on SP1Helios mock +log_info "Setting execution state root on SP1Helios mock..." +cast send "$SP1HELIOS_ADDRESS" \ + "setExecutionStateRoot(uint256,bytes32)" \ + "$SLOT_NUMBER" \ + "$EXECUTION_STATE_ROOT" \ + --rpc-url "$L2_RPC_URL" \ + --private-key "$PRIVATE_KEY" \ + > /dev/null 2>&1 + +# Create proof JSON file +jq -n \ + --arg middlewareBlockNumber "$MIDDLEWARE_BLOCK_NUMBER" \ + --arg slotNumber "$SLOT_NUMBER" \ + --arg storageHash "$(echo "$PROOF_DATA" | jq -r '.storageHash')" \ + --arg executionStateRoot "$EXECUTION_STATE_ROOT" \ + --argjson storageProof "$(echo "$PROOF_DATA" | jq -r '.storageProof[0].proof')" \ + --argjson accountProof "$(echo "$PROOF_DATA" | jq -r '.accountProof')" \ + '{ + "middlewareBlockNumber": $middlewareBlockNumber, + "slotNumber": $slotNumber, + "storageHash": $storageHash, + "executionStateRoot": $executionStateRoot, + "storageProof": $storageProof, + "accountProof": $accountProof + }' > "$PROOF_FILE" + +log_info "Mock proof saved to: $PROOF_FILE" + +####################################################################### +# Step 5: Update L2 Mimic (Bridge state) +####################################################################### + +log_info "Step 5: Bridging state to L2 mimic..." + +export PROOF_FILE +export REGISTRY_COORDINATOR_MIMIC_ADDRESS="$REGISTRY_COORDINATOR_MIMIC" +export BLS_SIGNATURE_CHECKER_ADDRESS="$BLS_SIGNATURE_CHECKER" +export MIDDLEWARE_SHIM_ADDRESS +export IS_SP1HELIOS_MOCK="true" +export L1_RPC_URL +export L2_RPC_URL +export PRIVATE_KEY + +forge script script/e2e/UpdateMimic.s.sol:UpdateMimic \ + --broadcast \ + --quiet + +log_info "State bridged successfully!" + +####################################################################### +# Verify bridged state +####################################################################### + +log_info "Verifying bridged state on L2..." + +QUORUM_COUNT=$(cast call "$REGISTRY_COORDINATOR_MIMIC" "quorumCount()(uint8)" --rpc-url "$L2_RPC_URL") +LAST_BLOCK=$(cast call "$REGISTRY_COORDINATOR_MIMIC" "lastBlockNumber()(uint32)" --rpc-url "$L2_RPC_URL") + +log_info "Verification complete:" +echo " - Quorum count: $QUORUM_COUNT" +echo " - Last updated block: $LAST_BLOCK" + +####################################################################### +# Summary +####################################################################### + +echo "" +echo "========================================" +echo "Bridge Complete!" +echo "========================================" +echo "" +echo "L1 Contracts ($(echo $L1_RPC_URL | sed 's|https://||' | cut -d'.' -f1)):" +echo " MiddlewareShim: $MIDDLEWARE_SHIM_ADDRESS" +echo "" +echo "L2 Contracts:" +echo " RegistryCoordinatorMimic: $REGISTRY_COORDINATOR_MIMIC" +echo " BLSSignatureChecker: $BLS_SIGNATURE_CHECKER" +echo " SP1HeliosMock: $SP1HELIOS_ADDRESS" +echo "" +echo "Deployment files:" +echo " L1: $L1_OUT_PATH" +echo " L2: $L2_OUT_PATH" +echo " Proof: $PROOF_FILE" +echo "" diff --git a/scripts/bridge.env.example b/scripts/bridge.env.example new file mode 100644 index 0000000..0ad3652 --- /dev/null +++ b/scripts/bridge.env.example @@ -0,0 +1,22 @@ +# Bridge Script Environment Variables +# Copy this file to bridge.env and fill in the values + +# Required: Private key for deployment and transactions +PRIVATE_KEY= + +# Required: L1 RPC URL (e.g., Sepolia, Holesky, Mainnet) +L1_RPC_URL= + +# Required: L2 RPC URL (e.g., Gnosis, Arbitrum, etc.) +L2_RPC_URL= + +# Required: Registry coordinator address on L1 to bridge from +REGISTRY_COORDINATOR_ADDRESS= + +# Optional: Slot number for mock proof (default: 12345) +# SLOT_NUMBER=12345 + +# Optional: Skip deployment and use existing contracts +# SKIP_DEPLOY=true +# L1_DEPLOY_FILE=/path/to/l1-deploy.json +# L2_DEPLOY_FILE=/path/to/l2-deploy.json