diff --git a/.github/scripts/extract_l1_addresses.sh b/.github/scripts/extract_l1_addresses.sh deleted file mode 100755 index b23d5c4bcca8..000000000000 --- a/.github/scripts/extract_l1_addresses.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env bash - -FILE_PATH=$1 - -# Read the file line by line -while IFS= read -r line; do - # Extract the hexadecimal address using awk - address=$(echo "$line" | awk '{print $NF}') - - # Assign the address to the respective variable based on the line content - if [[ $line == *"Rollup Address"* ]]; then - export TF_VAR_ROLLUP_CONTRACT_ADDRESS=$address - echo "TF_VAR_ROLLUP_CONTRACT_ADDRESS=$TF_VAR_ROLLUP_CONTRACT_ADDRESS" - elif [[ $line == *"Registry Address"* ]]; then - export TF_VAR_REGISTRY_CONTRACT_ADDRESS=$address - echo "TF_VAR_REGISTRY_CONTRACT_ADDRESS=$TF_VAR_REGISTRY_CONTRACT_ADDRESS" - elif [[ $line == *"Inbox Address"* ]]; then - export TF_VAR_INBOX_CONTRACT_ADDRESS=$address - echo "TF_VAR_INBOX_CONTRACT_ADDRESS=$TF_VAR_INBOX_CONTRACT_ADDRESS" - elif [[ $line == *"Outbox Address"* ]]; then - export TF_VAR_OUTBOX_CONTRACT_ADDRESS=$address - echo "TF_VAR_OUTBOX_CONTRACT_ADDRESS=$TF_VAR_OUTBOX_CONTRACT_ADDRESS" - elif [[ $line == *"Oracle Address"* ]]; then - export TF_VAR_AVAILABILITY_ORACLE_CONTRACT_ADDRESS=$address - echo "TF_VAR_AVAILABILITY_ORACLE_CONTRACT_ADDRESS=$TF_VAR_AVAILABILITY_ORACLE_CONTRACT_ADDRESS" - elif [[ $line == *"Gas Token Address"* ]]; then - export TF_VAR_GAS_TOKEN_CONTRACT_ADDRESS=$address - echo "TF_VAR_GAS_TOKEN_CONTRACT_ADDRESS=$TF_VAR_GAS_TOKEN_CONTRACT_ADDRESS" - elif [[ $line == *"Gas Portal Address"* ]]; then - export TF_VAR_GAS_PORTAL_CONTRACT_ADDRESS=$address - echo "TF_VAR_GAS_PORTAL_CONTRACT_ADDRESS=$TF_VAR_GAS_PORTAL_CONTRACT_ADDRESS" - else - echo "Unknown contract address: $line" - fi -done <"$FILE_PATH" - -# echo all addresses into github env -echo "TF_VAR_ROLLUP_CONTRACT_ADDRESS=$TF_VAR_ROLLUP_CONTRACT_ADDRESS" >>$GITHUB_ENV -echo "TF_VAR_REGISTRY_CONTRACT_ADDRESS=$TF_VAR_REGISTRY_CONTRACT_ADDRESS" >>$GITHUB_ENV -echo "TF_VAR_INBOX_CONTRACT_ADDRESS=$TF_VAR_INBOX_CONTRACT_ADDRESS" >>$GITHUB_ENV -echo "TF_VAR_OUTBOX_CONTRACT_ADDRESS=$TF_VAR_OUTBOX_CONTRACT_ADDRESS" >>$GITHUB_ENV -echo "TF_VAR_AVAILABILITY_ORACLE_CONTRACT_ADDRESS=$TF_VAR_AVAILABILITY_ORACLE_CONTRACT_ADDRESS" >>$GITHUB_ENV -echo "TF_VAR_GAS_TOKEN_CONTRACT_ADDRESS=$TF_VAR_GAS_TOKEN_CONTRACT_ADDRESS" >>$GITHUB_ENV -echo "TF_VAR_GAS_PORTAL_CONTRACT_ADDRESS=$TF_VAR_GAS_PORTAL_CONTRACT_ADDRESS" >>$GITHUB_ENV - -# Set global variable for redeployment of contracts -echo "CONTRACTS_DEPLOYED=1" >>$GITHUB_ENV diff --git a/.github/scripts/extract_output.sh b/.github/scripts/extract_output.sh new file mode 100755 index 000000000000..c6e8561b3403 --- /dev/null +++ b/.github/scripts/extract_output.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash + +TO_EXTRACT=$1 +FILE_PATH=$2 + +if [[ $TO_EXTRACT == "l1-contracts" ]]; then + # Extract l1 contract addresses + + JSON_OUTPUT='{' + + # Read the file line by line + while IFS= read -r line; do + # Extract the hexadecimal address using awk + address=$(echo "$line" | awk '{print $NF}') + + # Assign the address to the respective variable based on the line content + if [[ $line == *"Rollup Address"* ]]; then + export TF_VAR_ROLLUP_CONTRACT_ADDRESS=$address + JSON_OUTPUT+=' "rollup_contract_address": "'$address'",' + elif [[ $line == *"Registry Address"* ]]; then + export TF_VAR_REGISTRY_CONTRACT_ADDRESS=$address + JSON_OUTPUT+=' "registry_contract_address": "'$address'",' + elif [[ $line == *"Inbox Address"* ]]; then + export TF_VAR_INBOX_CONTRACT_ADDRESS=$address + JSON_OUTPUT+=' "inbox_contract_address": "'$address'",' + elif [[ $line == *"Outbox Address"* ]]; then + export TF_VAR_OUTBOX_CONTRACT_ADDRESS=$address + JSON_OUTPUT+=' "outbox_contract_address": "'$address'",' + elif [[ $line == *"Oracle Address"* ]]; then + export TF_VAR_AVAILABILITY_ORACLE_CONTRACT_ADDRESS=$address + JSON_OUTPUT+=' "availability_oracle_contract_address": "'$address'",' + elif [[ $line == *"Gas Token Address"* ]]; then + export TF_VAR_GAS_TOKEN_CONTRACT_ADDRESS=$address + JSON_OUTPUT+=' "gas_token_contract_address": "'$address'",' + elif [[ $line == *"Gas Portal Address"* ]]; then + export TF_VAR_GAS_PORTAL_CONTRACT_ADDRESS=$address + JSON_OUTPUT+=' "gas_portal_contract_address": "'$address'",' + else + echo "Unknown contract address: $line" + fi + done <"$FILE_PATH" + + # Remove the last comma and close the JSON object + JSON_OUTPUT=${JSON_OUTPUT%,} + JSON_OUTPUT+=' }' + + # echo all addresses into github env + echo "TF_VAR_ROLLUP_CONTRACT_ADDRESS=$TF_VAR_ROLLUP_CONTRACT_ADDRESS" >>$GITHUB_ENV + echo "TF_VAR_REGISTRY_CONTRACT_ADDRESS=$TF_VAR_REGISTRY_CONTRACT_ADDRESS" >>$GITHUB_ENV + echo "TF_VAR_INBOX_CONTRACT_ADDRESS=$TF_VAR_INBOX_CONTRACT_ADDRESS" >>$GITHUB_ENV + echo "TF_VAR_OUTBOX_CONTRACT_ADDRESS=$TF_VAR_OUTBOX_CONTRACT_ADDRESS" >>$GITHUB_ENV + echo "TF_VAR_AVAILABILITY_ORACLE_CONTRACT_ADDRESS=$TF_VAR_AVAILABILITY_ORACLE_CONTRACT_ADDRESS" >>$GITHUB_ENV + echo "TF_VAR_GAS_TOKEN_CONTRACT_ADDRESS=$TF_VAR_GAS_TOKEN_CONTRACT_ADDRESS" >>$GITHUB_ENV + echo "TF_VAR_GAS_PORTAL_CONTRACT_ADDRESS=$TF_VAR_GAS_PORTAL_CONTRACT_ADDRESS" >>$GITHUB_ENV + + # Output to JSON file + echo $JSON_OUTPUT >./l1-contracts.json + +elif [[ $TO_EXTRACT == "account" ]]; then + # Extract aztec account private key + OUTPUT=$(cat $FILE_PATH) + + AZTEC_PRIVATE_KEY=$(echo "$OUTPUT" | grep "Private key:" | awk '{print $NF}') + AZTEC_ADDRESS=$(echo "$OUTPUT" | grep "Address:" | awk '{print $NF}') + + # Print the private key and address into github env + echo "AZTEC_PRIVATE_KEY=$AZTEC_PRIVATE_KEY" >>$GITHUB_ENV + echo "AZTEC_ADDRESS=$AZTEC_ADDRESS" >>$GITHUB_ENV + + # Export + export AZTEC_PRIVATE_KEY=$AZTEC_PRIVATE_KEY + export AZTEC_ADDRESS=$AZTEC_ADDRESS + +elif [[ $TO_EXTRACT == "l2-bootstrap" ]]; then + # Extract l2 bootstrap contract addresses + + # Read the log output from a file + OUTPUT=$(cat $FILE_PATH) + + KEY_REGISTRY_ADDRESS=$(echo "$OUTPUT" | grep "Deployed Key Registry on L2 at" | awk '{print $NF}') + + AUTH_REGISTRY_ADDRESS=$(echo "$OUTPUT" | grep "Deployed Auth Registry on L2 at" | awk '{print $NF}') + + FEE_JUICE_ADDRESS=$(echo "$OUTPUT" | grep "Deployed Gas Token on L2 at" | awk '{print $NF}') + + # Print the extracted into github env + echo "KEY_REGISTRY_ADDRESS=$KEY_REGISTRY_ADDRESS" >>$GITHUB_ENV + echo "AUTH_REGISTRY_ADDRESS=$AUTH_REGISTRY_ADDRESS" >>$GITHUB_ENV + echo "FEE_JUICE_ADDRESS=$FEE_JUICE_ADDRESS" >>$GITHUB_ENV + + # Export + export KEY_REGISTRY_ADDRESS=$KEY_REGISTRY_ADDRESS + export AUTH_REGISTRY_ADDRESS=$AUTH_REGISTRY_ADDRESS + export FEE_JUICE_ADDRESS=$FEE_JUICE_ADDRESS + +elif [[ $TO_EXTRACT == "l2-contract" ]]; then + # Extract l2 contract addresses + + TOKEN_CONTRACT_NAME=$3 + + OUTPUT=$(cat $FILE_PATH) + + CONTRACT_ADDRESS=$(echo "$OUTPUT" | grep "Contract deployed at" | awk '{print $NF}') + + echo "$TOKEN_CONTRACT_NAME=$CONTRACT_ADDRESS" >>$GITHUB_ENV + + # Export + export $TOKEN_CONTRACT_NAME=$CONTRACT_ADDRESS +fi diff --git a/.github/scripts/wait_for_fork.sh b/.github/scripts/wait_for_fork.sh deleted file mode 100755 index c6952e9fbab4..000000000000 --- a/.github/scripts/wait_for_fork.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -set -e - -DEPLOY_TAG=$1 -TEST_FORK_API_KEY=$2 - -# When destroying and applying mainnet fork terraform, it may not be -# ready for a while, as it must register with DNS etc. -# This script waits on a healthy status from the fork - a valid response to the chainid request -# We retry every 20 seconds, and wait for a total of 5 minutes (15 times) -export ETHEREUM_HOST="https://$DEPLOY_TAG-mainnet-fork.aztec.network:8545/$TEST_FORK_API_KEY" - -curl -H "Content-Type: application/json" -X POST --data '{"method":"eth_chainId","params":[],"id":49,"jsonrpc":"2.0"}' \ - --connect-timeout 30 \ - --retry 15 \ - --retry-delay 20 \ - $ETHEREUM_HOST diff --git a/.github/scripts/wait_for_infra.sh b/.github/scripts/wait_for_infra.sh new file mode 100755 index 000000000000..d202e6cbcdd2 --- /dev/null +++ b/.github/scripts/wait_for_infra.sh @@ -0,0 +1,30 @@ +#!/bin/bash +set -e + +INFRA=$1 +DEPLOY_TAG=$2 +API_KEY=$3 + +# When destroying and applying terraforms, they may not be +# ready for a while, as it must register with DNS etc. +# This script waits on a healthy status from the infra - a valid response to a request +# We retry every 20 seconds, and wait for a total of 5 minutes (15 times) + +if [ "$INFRA" == "mainnet-fork" ]; then + export ETHEREUM_HOST="https://$DEPLOY_TAG-mainnet-fork.aztec.network:8545/$API_KEY" + curl -H "Content-Type: application/json" -X POST --data '{"method":"eth_chainId","params":[],"id":49,"jsonrpc":"2.0"}' \ + --connect-timeout 30 \ + --retry 15 \ + --retry-delay 20 \ + $ETHEREUM_HOST +elif [ "$INFRA" == "pxe" ]; then + export PXE_URL="https://api.aztec.network/$DEPLOY_TAG/aztec-pxe/$API_KEY/status" + curl \ + --connect-timeout 30 \ + --retry 15 \ + --retry-delay 20 \ + $PXE_URL +else + echo "Invalid infra type" + exit 1 +fi diff --git a/.github/workflows/devnet-deploys.yml b/.github/workflows/devnet-deploys.yml index fef1b0d382ae..223cb7177c4b 100644 --- a/.github/workflows/devnet-deploys.yml +++ b/.github/workflows/devnet-deploys.yml @@ -11,7 +11,6 @@ env: DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} GIT_COMMIT: ${{ github.sha }} DEPLOY_TAG: devnet - FILE_PATH: ./l1-contracts/addresses.txt L1_CHAIN_ID: 677692 AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} @@ -34,13 +33,9 @@ jobs: username: master runner_type: builder-x86 secrets: inherit - build: needs: setup runs-on: ${{ github.actor }}-x86 - outputs: - l1_contracts_changed: ${{ steps.check_l1_changes.outputs.result }} - mainnet_fork_changed: ${{ steps.check_fork_changes.outputs.result }} steps: - uses: actions/checkout@v4 with: @@ -52,21 +47,10 @@ jobs: dockerhub_password: "${{ secrets.DOCKERHUB_PASSWORD }}" - name: "Build & Push aztec images" timeout-minutes: 40 - # Run the build steps for each image with version and arch, push to dockerhub run: | earthly-ci \ --no-output --push ./yarn-project+export-aztec-arch --DIST_TAG=${{ env.DEPLOY_TAG }} - - name: Check if L1 contracts need deployment - id: check_l1_changes - uses: actions/github-script@v7 - with: - script: | - const { execSync } = require('child_process'); - const changedFiles = execSync('git diff --name-only ${{ github.event.before }} ${{ github.sha }}').toString().split('\n'); - const fileChanged = changedFiles.some(file => file.startsWith('l1-contracts')); - return fileChanged - - name: Check if mainnet fork needs deployment id: check_fork_changes uses: actions/github-script@v7 @@ -104,59 +88,127 @@ jobs: aws-region: eu-west-2 - name: Deploy mainnet fork - if: needs.build.outputs.mainnet_fork_changed == 'true' working-directory: ./iac/mainnet-fork/terraform run: | terraform init -input=false -backend-config="key=${{ env.DEPLOY_TAG }}/mainnet-fork" - terraform apply -input=false -auto-approve -replace="aws_ecs_service.aztec_mainnet_fork" -replace="aws_efs_file_system.aztec_mainnet_fork_data_store" + terraform apply -input=false -auto-approve -replace="aws_efs_file_system.aztec_mainnet_fork_data_store" - name: Wait for mainnet fork deployment - if: needs.build.outputs.mainnet_fork_changed == 'true' run: | - ./.github/scripts/wait_for_fork.sh ${{ env.DEPLOY_TAG }} ${{ secrets.FORK_API_KEY }} + ./.github/scripts/wait_for_infra.sh mainnet-fork ${{ env.DEPLOY_TAG }} ${{ secrets.FORK_API_KEY }} - name: Deploy L1 Contracts - if: needs.build.outputs.l1_contracts_changed == 'true' || needs.build.outputs.mainnet_fork_changed == 'true' run: | docker pull aztecprotocol/aztec:${{ env.DEPLOY_TAG }} docker run aztecprotocol/aztec:${{ env.DEPLOY_TAG }} deploy-l1-contracts \ --private-key ${{ secrets.SEQ_1_PUBLISHER_PRIVATE_KEY }} \ --rpc-url https://${{ env.DEPLOY_TAG }}-mainnet-fork.aztec.network:8545/${{ secrets.FORK_API_KEY }} \ --l1-chain-id ${{ env.L1_CHAIN_ID }} \ - | tee ${{ env.FILE_PATH }} - ./.github/scripts/extract_l1_addresses.sh ${{ env.FILE_PATH }} + | tee ./l1-contracts/addresses.txt + ./.github/scripts/extract_output.sh l1-contracts ./l1-contracts/addresses.txt - name: Apply l1-contracts Terraform - if: needs.build.outputs.l1_contracts_changed == 'true' || needs.build.outputs.mainnet_fork_changed == 'true' working-directory: ./l1-contracts/terraform run: | terraform init -input=false -backend-config="key=${{ env.DEPLOY_TAG }}/l1-contracts" terraform apply -input=false -auto-approve - - name: Deploy P2P Bootstrap Nodes - working-directory: ./yarn-project/p2p-bootstrap/terraform + - name: Upload L1 contract addresses to S3 run: | - terraform init -input=false -backend-config="key=${{ env.DEPLOY_TAG }}/p2p-bootstrap" - terraform apply -input=false -auto-approve + aws s3 cp ./l1-contracts.json s3://aztec-${{ env.DEPLOY_TAG }}-deployments/l1_contract_addresses.json - name: Init Aztec Node Terraform working-directory: ./yarn-project/aztec/terraform/node run: | terraform init -input=false -backend-config="key=${{ env.DEPLOY_TAG }}/aztec-node" - - name: Taint node filesystem if L1 contracts are redeployed - if: needs.build.outputs.l1_contracts_changed == 'true' - working-directory: ./yarn-project/aztec/terraform/node - run: | - terraform taint aws_efs_file_system.node_data_store - - name: Deploy Aztec Nodes working-directory: ./yarn-project/aztec/terraform/node run: | - terraform apply -input=false -auto-approve + terraform apply -input=false -auto-approve -replace="aws_efs_file_system.node_data_store" - name: Deploy Provers working-directory: ./yarn-project/aztec/terraform/prover run: | terraform init -input=false -backend-config="key=${{ env.DEPLOY_TAG }}/prover" terraform apply -input=false -auto-approve + + - name: Deploy PXE + working-directory: ./yarn-project/aztec/terraform/pxe + run: | + terraform init -input=false -backend-config="key=${{ env.DEPLOY_TAG }}/pxe" + terraform apply -input=false -auto-approve + + - name: Deploy P2P Bootstrap Nodes + working-directory: ./yarn-project/p2p-bootstrap/terraform + run: | + terraform init -input=false -backend-config="key=${{ env.DEPLOY_TAG }}/p2p-bootstrap" + terraform apply -input=false -auto-approve + + bootstrap: + runs-on: ubuntu-latest + needs: terraform_deploy + steps: + - uses: actions/checkout@v4 + with: + ref: "${{ env.GIT_COMMIT }}" + + - uses: ./.github/ci-setup-action + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: eu-west-2 + + - name: Wait for PXE to be available + run: | + ./.github/scripts/wait_for_infra.sh pxe ${{ env.DEPLOY_TAG }} ${{ secrets.FORK_API_KEY }} + + - name: Bootstrap devnet + run: | + docker pull aztecprotocol/aztec:${{ env.DEPLOY_TAG }} + docker run aztecprotocol/aztec:${{ env.DEPLOY_TAG }} bootstrap \ + --rpc-url https://api.aztec.network/${{ env.DEPLOY_TAG }}/aztec-pxe/${{ secrets.FORK_API_KEY }} \ + --l1-chain-id ${{ env.L1_CHAIN_ID }} \ + | tee ./bootstrap_addresses.txt + source ./.github/scripts/extract_output.sh l2-bootstrap ./bootstrap_addresses.txt + + - name: Deploy contracts + run: | + docker run aztecprotocol/aztec:${{ env.DEPLOY_TAG }} create-account \ + --rpc-url https://api.aztec.network/${{ env.DEPLOY_TAG }}/aztec-pxe/${{ secrets.FORK_API_KEY }} \ + | tee ./account.txt + source ./.github/scripts/extract_output.sh account ./account.txt + echo "PK: $AZTEC_PRIVATE_KEY" + echo "CA: $AZTEC_ADDRESS" + docker run aztecprotocol/aztec:${{ env.DEPLOY_TAG }} deploy TokenContract \ + --rpc-url https://api.aztec.network/${{ env.DEPLOY_TAG }}/aztec-pxe/${{ secrets.FORK_API_KEY }} \ + --args $AZTEC_ADDRESS DevCoin DEV 18 \ + --private-key $AZTEC_PRIVATE_KEY \ + --public-deployment \ + --class-registration \ + | tee ./token_contract.txt + source ./.github/scripts/extract_output.sh l2-contract ./token_contract.txt TOKEN_CONTRACT_ADDRESS + + docker run aztecprotocol/aztec:${{ env.DEPLOY_TAG }} deploy FPCContract \ + --rpc-url https://api.aztec.network/${{ env.DEPLOY_TAG }}/aztec-pxe/${{ secrets.FORK_API_KEY }} \ + --args $TOKEN_CONTRACT_ADDRESS $FEE_JUICE_ADDRESS \ + --private-key $AZTEC_PRIVATE_KEY \ + --public-deployment \ + --class-registration \ + | tee ./fpc_contract.txt + source ./.github/scripts/extract_output.sh l2-contract ./fpc_contract.txt FPC_CONTRACT_ADDRESS + + - name: Upload addreses to S3 + run: | + echo '{ + "fee_juice_address": "'$FEE_JUICE_ADDRESS'", + "key_registry_address": "'$KEY_REGISTRY_ADDRESS'", + "auth_registry_address": "'$AUTH_REGISTRY_ADDRESS'", + "token_contract_address": "'$TOKEN_CONTRACT_ADDRESS'", + "fpc_contract_address": "'$FPC_CONTRACT_ADDRESS' + }' > ./l2_addresses.json + + aws s3 cp ./l2_addresses.json s3://aztec-${{ env.DEPLOY_TAG }}-deployments/l2_contract_addresses.json diff --git a/iac/mainnet-fork/scripts/run_nginx_anvil.sh b/iac/mainnet-fork/scripts/run_nginx_anvil.sh index e7cf5d595368..d73fb885f6cc 100755 --- a/iac/mainnet-fork/scripts/run_nginx_anvil.sh +++ b/iac/mainnet-fork/scripts/run_nginx_anvil.sh @@ -18,7 +18,7 @@ echo "stripping double quotations from the mnemonic seed phrase: ${MNEMONIC:0:10 MNEMONIC_STRIPPED=${MNEMONIC//\"/} echo "result: ${MNEMONIC_STRIPPED:0:10}..." -# Data directory for anvil state. +# Data directory for anvil state mkdir -p /data # Run anvil silently diff --git a/l1-contracts/REDEPLOY b/l1-contracts/REDEPLOY index 595f09288f85..456b5196b3d3 100644 --- a/l1-contracts/REDEPLOY +++ b/l1-contracts/REDEPLOY @@ -1,2 +1,2 @@ # Change value to force redeploy -1 +1 \ No newline at end of file diff --git a/l1-contracts/terraform/main.tf b/l1-contracts/terraform/main.tf index b5d237b047e8..bc5916b2110b 100644 --- a/l1-contracts/terraform/main.tf +++ b/l1-contracts/terraform/main.tf @@ -11,6 +11,15 @@ terraform { } } +variable "DEPLOY_TAG" { + type = string +} + +# S3 Bucket to store contract addresses +resource "aws_s3_bucket" "contract_addresses" { + bucket = "aztec-${var.DEPLOY_TAG}-deployments" +} + variable "ROLLUP_CONTRACT_ADDRESS" { type = string default = "" diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index ea5fba3f345d..f58ba765be41 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -27,6 +27,7 @@ export { type ContractMethod, type ContractNotes, type ContractStorageLayout, + DefaultWaitOpts, DeployMethod, DeploySentTx, type SendMethodOptions, diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index 84799e61d5f7..857917469417 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -16,6 +16,7 @@ "scripts": { "build": "yarn clean && tsc -b", "start": "node --no-warnings ./dest/bin", + "start:debug": "node --inspect=0.0.0.0:9221 --no-warnings ./dest/bin", "clean": "rm -rf ./dest .tsbuildinfo", "formatting": "run -T prettier --check ./src && run -T eslint ./src", "formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src", diff --git a/yarn-project/aztec/src/sandbox.ts b/yarn-project/aztec/src/sandbox.ts index 570b4a620ec3..7d7eb8038131 100644 --- a/yarn-project/aztec/src/sandbox.ts +++ b/yarn-project/aztec/src/sandbox.ts @@ -1,12 +1,11 @@ #!/usr/bin/env -S node --no-warnings import { type AztecNodeConfig, AztecNodeService, getConfigEnvVars } from '@aztec/aztec-node'; -import { AztecAddress, SignerlessWallet, type Wallet } from '@aztec/aztec.js'; +import { SignerlessWallet } from '@aztec/aztec.js'; import { DefaultMultiCallEntrypoint } from '@aztec/aztec.js/entrypoint'; import { type AztecNode } from '@aztec/circuit-types'; -import { CANONICAL_AUTH_REGISTRY_ADDRESS, CANONICAL_KEY_REGISTRY_ADDRESS } from '@aztec/circuits.js'; +import { deployCanonicalAuthRegistry, deployCanonicalKeyRegistry, deployCanonicalL2GasToken } from '@aztec/cli/utils'; import { type DeployL1Contracts, - type L1ContractAddresses, type L1ContractArtifactsForDeployment, NULL_KEY, createEthereumChain, @@ -30,12 +29,8 @@ import { RollupAbi, RollupBytecode, } from '@aztec/l1-artifacts'; -import { AuthRegistryContract, KeyRegistryContract } from '@aztec/noir-contracts.js'; -import { GasTokenContract } from '@aztec/noir-contracts.js/GasToken'; import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types'; -import { getCanonicalAuthRegistry } from '@aztec/protocol-contracts/auth-registry'; -import { GasTokenAddress, getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token'; -import { getCanonicalKeyRegistry } from '@aztec/protocol-contracts/key-registry'; +import { GasTokenAddress } from '@aztec/protocol-contracts/gas-token'; import { type PXEServiceConfig, createPXEService, getPXEServiceConfig } from '@aztec/pxe'; import { type TelemetryClient } from '@aztec/telemetry-client'; import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; @@ -136,101 +131,6 @@ export async function deployContractsToL1( return aztecNodeConfig.l1Contracts; } -/** - * Deploys the contract to pay for gas on L2. - */ -async function deployCanonicalL2GasToken(deployer: Wallet, l1ContractAddresses: L1ContractAddresses) { - const gasPortalAddress = l1ContractAddresses.gasPortalAddress; - const canonicalGasToken = getCanonicalGasToken(); - - if (await deployer.isContractClassPubliclyRegistered(canonicalGasToken.contractClass.id)) { - return; - } - - const gasToken = await GasTokenContract.deploy(deployer) - .send({ universalDeploy: true, contractAddressSalt: canonicalGasToken.instance.salt }) - .deployed(); - await gasToken.methods.set_portal(gasPortalAddress).send().wait(); - - if (!gasToken.address.equals(canonicalGasToken.address)) { - throw new Error( - `Deployed Gas Token address ${gasToken.address} does not match expected address ${canonicalGasToken.address}`, - ); - } - - if (!(await deployer.isContractPubliclyDeployed(canonicalGasToken.address))) { - throw new Error(`Failed to deploy Gas Token to ${canonicalGasToken.address}`); - } - - logger.info(`Deployed Gas Token on L2 at ${canonicalGasToken.address}`); -} - -/** - * Deploys the key registry on L2. - */ -async function deployCanonicalKeyRegistry(deployer: Wallet) { - const canonicalKeyRegistry = getCanonicalKeyRegistry(); - - // We check to see if there exists a contract at the canonical Key Registry address with the same contract class id as we expect. This means that - // the key registry has already been deployed to the correct address. - if ( - (await deployer.getContractInstance(canonicalKeyRegistry.address))?.contractClassId.equals( - canonicalKeyRegistry.contractClass.id, - ) && - (await deployer.isContractClassPubliclyRegistered(canonicalKeyRegistry.contractClass.id)) - ) { - return; - } - - const keyRegistry = await KeyRegistryContract.deploy(deployer) - .send({ contractAddressSalt: canonicalKeyRegistry.instance.salt, universalDeploy: true }) - .deployed(); - - if ( - !keyRegistry.address.equals(canonicalKeyRegistry.address) || - !keyRegistry.address.equals(AztecAddress.fromBigInt(CANONICAL_KEY_REGISTRY_ADDRESS)) - ) { - throw new Error( - `Deployed Key Registry address ${keyRegistry.address} does not match expected address ${canonicalKeyRegistry.address}, or they both do not equal CANONICAL_KEY_REGISTRY_ADDRESS`, - ); - } - - logger.info(`Deployed Key Registry on L2 at ${canonicalKeyRegistry.address}`); -} - -/** - * Deploys the auth registry on L2. - */ -async function deployCanonicalAuthRegistry(deployer: Wallet) { - const canonicalAuthRegistry = getCanonicalAuthRegistry(); - - // We check to see if there exists a contract at the canonical Auth Registry address with the same contract class id as we expect. This means that - // the auth registry has already been deployed to the correct address. - if ( - (await deployer.getContractInstance(canonicalAuthRegistry.address))?.contractClassId.equals( - canonicalAuthRegistry.contractClass.id, - ) && - (await deployer.isContractClassPubliclyRegistered(canonicalAuthRegistry.contractClass.id)) - ) { - return; - } - - const authRegistry = await AuthRegistryContract.deploy(deployer) - .send({ contractAddressSalt: canonicalAuthRegistry.instance.salt, universalDeploy: true }) - .deployed(); - - if ( - !authRegistry.address.equals(canonicalAuthRegistry.address) || - !authRegistry.address.equals(AztecAddress.fromBigInt(CANONICAL_AUTH_REGISTRY_ADDRESS)) - ) { - throw new Error( - `Deployed Auth Registry address ${authRegistry.address} does not match expected address ${canonicalAuthRegistry.address}, or they both do not equal CANONICAL_AUTH_REGISTRY_ADDRESS`, - ); - } - - logger.info(`Deployed Auth Registry on L2 at ${canonicalAuthRegistry.address}`); -} - /** Sandbox settings. */ export type SandboxConfig = AztecNodeConfig & { /** Mnemonic used to derive the L1 deployer private key.*/ @@ -261,15 +161,18 @@ export async function createSandbox(config: Partial = {}) { await deployCanonicalKeyRegistry( new SignerlessWallet(pxe, new DefaultMultiCallEntrypoint(aztecNodeConfig.l1ChainId, aztecNodeConfig.version)), + logger.info, ); await deployCanonicalAuthRegistry( new SignerlessWallet(pxe, new DefaultMultiCallEntrypoint(aztecNodeConfig.l1ChainId, aztecNodeConfig.version)), + logger.info, ); if (config.enableGas) { await deployCanonicalL2GasToken( new SignerlessWallet(pxe, new DefaultMultiCallEntrypoint(aztecNodeConfig.l1ChainId, aztecNodeConfig.version)), - aztecNodeConfig.l1Contracts, + aztecNodeConfig.l1Contracts.gasPortalAddress, + logger.info, ); } diff --git a/yarn-project/aztec/terraform/node/variables.tf b/yarn-project/aztec/terraform/node/variables.tf index 90b9919a0e3d..1efc9f94faf8 100644 --- a/yarn-project/aztec/terraform/node/variables.tf +++ b/yarn-project/aztec/terraform/node/variables.tf @@ -70,5 +70,5 @@ variable "P2P_ENABLED" { variable "PROVING_ENABLED" { type = bool - default = true + default = false } diff --git a/yarn-project/aztec/terraform/prover/main.tf b/yarn-project/aztec/terraform/prover/main.tf index a9034ad7bc7c..1d131d937846 100644 --- a/yarn-project/aztec/terraform/prover/main.tf +++ b/yarn-project/aztec/terraform/prover/main.tf @@ -127,7 +127,7 @@ resource "aws_ecs_task_definition" "aztec-proving-agent" { }, { "name": "AZTEC_NODE_URL", - "value": "http://${var.DEPLOY_TAG}-aztec-node-${count.index + 1}.local/${var.DEPLOY_TAG}/aztec-node-${count.index + 1}" + "value": "http://${var.DEPLOY_TAG}-aztec-node-${count.index + 1}.local/${var.DEPLOY_TAG}/aztec-node-${count.index + 1}/${var.API_KEY}" }, { "name": "PROVER_AGENTS", diff --git a/yarn-project/aztec/terraform/prover/variables.tf b/yarn-project/aztec/terraform/prover/variables.tf index e6c6865d26d3..8dbad11e8106 100644 --- a/yarn-project/aztec/terraform/prover/variables.tf +++ b/yarn-project/aztec/terraform/prover/variables.tf @@ -9,9 +9,13 @@ variable "AGENTS_PER_SEQUENCER" { variable "PROVING_ENABLED" { type = bool - default = true + default = false } variable "DOCKERHUB_ACCOUNT" { type = string } + +variable "API_KEY" { + type = string +} diff --git a/yarn-project/aztec/terraform/pxe/main.tf b/yarn-project/aztec/terraform/pxe/main.tf new file mode 100644 index 000000000000..a648a83a78dc --- /dev/null +++ b/yarn-project/aztec/terraform/pxe/main.tf @@ -0,0 +1,238 @@ +terraform { + backend "s3" { + bucket = "aztec-terraform" + region = "eu-west-2" + } + required_providers { + aws = { + source = "hashicorp/aws" + version = "3.74.2" + } + } +} + +# Define provider and region +provider "aws" { + region = "eu-west-2" +} + +data "terraform_remote_state" "aztec2_iac" { + backend = "s3" + config = { + bucket = "aztec-terraform" + key = "aztec2/iac" + region = "eu-west-2" + } +} + +data "terraform_remote_state" "setup_iac" { + backend = "s3" + config = { + bucket = "aztec-terraform" + key = "setup/setup-iac" + region = "eu-west-2" + } +} + +resource "aws_cloudwatch_log_group" "aztec-pxe-log-group" { + name = "/fargate/service/${var.DEPLOY_TAG}/aztec-pxe" + retention_in_days = 14 +} + +resource "aws_service_discovery_service" "aztec-pxe" { + name = "${var.DEPLOY_TAG}-aztec-pxe" + + health_check_custom_config { + failure_threshold = 1 + } + + dns_config { + namespace_id = data.terraform_remote_state.setup_iac.outputs.local_service_discovery_id + + dns_records { + ttl = 60 + type = "A" + } + + dns_records { + ttl = 60 + type = "SRV" + } + + routing_policy = "MULTIVALUE" + } + + # Terraform just fails if this resource changes and you have registered instances. + provisioner "local-exec" { + when = destroy + command = "${path.module}/servicediscovery-drain.sh ${self.id}" + } +} + +resource "aws_efs_file_system" "pxe_data_store" { + creation_token = "${var.DEPLOY_TAG}-pxe-data" + throughput_mode = "provisioned" + provisioned_throughput_in_mibps = 20 + + tags = { + Name = "${var.DEPLOY_TAG}-pxe-data" + } + + lifecycle_policy { + transition_to_ia = "AFTER_14_DAYS" + } +} + +resource "aws_efs_mount_target" "public_az1" { + file_system_id = aws_efs_file_system.pxe_data_store.id + subnet_id = data.terraform_remote_state.setup_iac.outputs.subnet_az1_id + security_groups = [data.terraform_remote_state.setup_iac.outputs.security_group_public_id] +} + +resource "aws_efs_mount_target" "public_az2" { + file_system_id = aws_efs_file_system.pxe_data_store.id + subnet_id = data.terraform_remote_state.setup_iac.outputs.subnet_az2_id + security_groups = [data.terraform_remote_state.setup_iac.outputs.security_group_public_id] +} + +locals { + data_dir = "/usr/src/yarn-project/pxe/data" + api_prefix = "/${var.DEPLOY_TAG}/aztec-pxe/${var.API_KEY}" +} + + + +resource "aws_ecs_task_definition" "aztec-pxe" { + family = "${var.DEPLOY_TAG}-aztec-pxe" + network_mode = "awsvpc" + cpu = 2048 + memory = 4096 + requires_compatibilities = ["FARGATE"] + execution_role_arn = data.terraform_remote_state.setup_iac.outputs.ecs_task_execution_role_arn + task_role_arn = data.terraform_remote_state.aztec2_iac.outputs.cloudwatch_logging_ecs_role_arn + + volume { + name = "efs-data-store" + efs_volume_configuration { + file_system_id = aws_efs_file_system.pxe_data_store.id + } + } + + container_definitions = jsonencode([ + { + name = "${var.DEPLOY_TAG}-aztec-pxe" + image = "${var.DOCKERHUB_ACCOUNT}/aztec:${var.DEPLOY_TAG}" + command = ["start", "--pxe"] + essential = true + portMappings = [ + { + containerPort = 80 + hostPort = 80 + } + ] + environment = [ + { + name = "AZTEC_NODE_URL" + value = "http://${var.DEPLOY_TAG}-aztec-node-1.local/${var.DEPLOY_TAG}/aztec-node-1/${var.API_KEY}" + }, + { + name = "AZTEC_PORT" + value = "80" + }, + { + name = "PXE_DATA_DIRECTORY" + value = local.data_dir + }, + { + name = "API_PREFIX" + value = local.api_prefix + } + ] + mountPoints = [ + { + containerPath = local.data_dir + sourceVolume = "efs-data-store" + } + ] + logConfiguration = { + logDriver = "awslogs" + options = { + "awslogs-group" = aws_cloudwatch_log_group.aztec-pxe-log-group.name + "awslogs-region" = "eu-west-2" + "awslogs-stream-prefix" = "ecs" + } + } + } + ]) +} + +resource "aws_ecs_service" "aztec-pxe" { + name = "${var.DEPLOY_TAG}-aztec-pxe" + cluster = data.terraform_remote_state.setup_iac.outputs.ecs_cluster_id + launch_type = "FARGATE" + desired_count = 1 + deployment_maximum_percent = 100 + deployment_minimum_healthy_percent = 0 + platform_version = "1.4.0" + force_new_deployment = true + + network_configuration { + subnets = [ + data.terraform_remote_state.setup_iac.outputs.subnet_az1_private_id, + data.terraform_remote_state.setup_iac.outputs.subnet_az2_private_id + ] + security_groups = [data.terraform_remote_state.setup_iac.outputs.security_group_private_id] + } + + load_balancer { + target_group_arn = aws_alb_target_group.pxe_http.arn + container_name = "${var.DEPLOY_TAG}-aztec-pxe" + container_port = 80 + } + + service_registries { + registry_arn = aws_service_discovery_service.aztec-pxe.arn + container_name = "${var.DEPLOY_TAG}-aztec-pxe" + container_port = 80 + } + + task_definition = aws_ecs_task_definition.aztec-pxe.family +} + +resource "aws_alb_target_group" "pxe_http" { + name = "${var.DEPLOY_TAG}-pxe-http" + port = 80 + protocol = "HTTP" + target_type = "ip" + vpc_id = data.terraform_remote_state.setup_iac.outputs.vpc_id + deregistration_delay = 5 + + health_check { + path = "${local.api_prefix}/status" + matcher = 200 + interval = 10 + healthy_threshold = 2 + unhealthy_threshold = 5 + timeout = 5 + } + + tags = { + name = "${var.DEPLOY_TAG}-pxe-http" + } +} + +resource "aws_lb_listener_rule" "pxe_api" { + listener_arn = data.terraform_remote_state.aztec2_iac.outputs.alb_listener_arn + priority = 400 + + action { + type = "forward" + target_group_arn = aws_alb_target_group.pxe_http.arn + } + + condition { + path_pattern { + values = ["${local.api_prefix}*"] + } + } +} diff --git a/yarn-project/aztec/terraform/pxe/variables.tf b/yarn-project/aztec/terraform/pxe/variables.tf new file mode 100644 index 000000000000..d7e7eaff50ae --- /dev/null +++ b/yarn-project/aztec/terraform/pxe/variables.tf @@ -0,0 +1,11 @@ +variable "DEPLOY_TAG" { + type = string +} + +variable "DOCKERHUB_ACCOUNT" { + type = string +} + +variable "API_KEY" { + type = string +} diff --git a/yarn-project/cli/src/cmds/infrastructure/bootstrap.ts b/yarn-project/cli/src/cmds/infrastructure/bootstrap.ts index 0f862f8d90e9..a7eabefd9de7 100644 --- a/yarn-project/cli/src/cmds/infrastructure/bootstrap.ts +++ b/yarn-project/cli/src/cmds/infrastructure/bootstrap.ts @@ -1,49 +1,32 @@ import { SignerlessWallet, type WaitOpts, createPXEClient, makeFetch } from '@aztec/aztec.js'; import { DefaultMultiCallEntrypoint } from '@aztec/aztec.js/entrypoint'; import { type LogFn } from '@aztec/foundation/log'; -import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token'; -import { getCanonicalKeyRegistry } from '@aztec/protocol-contracts/key-registry'; + +import { + deployCanonicalAuthRegistry, + deployCanonicalKeyRegistry, + deployCanonicalL2GasToken, +} from '../utils/deploy_contracts.js'; const waitOpts: WaitOpts = { - timeout: 1800, + timeout: 180, interval: 1, }; export async function bootstrap(rpcUrl: string, l1ChainId: number, log: LogFn) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - Importing noir-contracts.js even in devDeps results in a circular dependency error. Need to ignore because this line doesn't cause an error in a dev environment - const { GasTokenContract, KeyRegistryContract } = await import('@aztec/noir-contracts.js'); - + // const { TokenContract } = await import('@aztec/noir-contracts.js'); const pxe = createPXEClient(rpcUrl, makeFetch([], true)); const deployer = new SignerlessWallet(pxe, new DefaultMultiCallEntrypoint(l1ChainId, 1)); - const canonicalKeyRegistry = getCanonicalKeyRegistry(); - const keyRegistryDeployParams = { - contractAddressSalt: canonicalKeyRegistry.instance.salt, - universalDeploy: true, - }; - const keyRegistryTx = KeyRegistryContract.deploy(deployer); - - const gasPortalAddress = (await deployer.getNodeInfo()).l1ContractAddresses.gasPortalAddress; - const canonicalGasToken = getCanonicalGasToken(); - const gasTokenDeployParams = { - contractAddressSalt: canonicalGasToken.instance.salt, - universalDeploy: true, - }; - const gasTokenTx = GasTokenContract.deploy(deployer); + // Deploy Key Registry + await deployCanonicalKeyRegistry(deployer, log, waitOpts); - // prove these txs sequentially otherwise global fetch with default options times out with real proofs - await keyRegistryTx.prove(keyRegistryDeployParams); - const keyRegistry = await keyRegistryTx.send(keyRegistryDeployParams).deployed(waitOpts); + // Deploy Auth Registry + await deployCanonicalAuthRegistry(deployer, log, waitOpts); - await gasTokenTx.prove(gasTokenDeployParams); - // also deploy the accounts sequentially otherwise there's too much data and publishing TxEffects fails - const gasToken = await gasTokenTx.send(gasTokenDeployParams).deployed(waitOpts); - - log(`Key Registry deployed at canonical address ${keyRegistry.address.toString()}`); - log(`Gas token deployed at canonical address ${gasToken.address.toString()}`); - - const portalSetTx = gasToken.methods.set_portal(gasPortalAddress); - await portalSetTx.prove(); - portalSetTx.send(); + // Deploy Fee Juice + const gasPortalAddress = (await deployer.getNodeInfo()).l1ContractAddresses.gasPortalAddress; + await deployCanonicalL2GasToken(deployer, gasPortalAddress, log, waitOpts); } diff --git a/yarn-project/cli/src/cmds/l1/index.ts b/yarn-project/cli/src/cmds/l1/index.ts index c9a276cfd952..01518316ce0b 100644 --- a/yarn-project/cli/src/cmds/l1/index.ts +++ b/yarn-project/cli/src/cmds/l1/index.ts @@ -21,7 +21,7 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: DebugL 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', ETHEREUM_HOST, ) - .requiredOption('-p, --private-key ', 'The private key to use for deployment', PRIVATE_KEY) + .requiredOption('-pk, --private-key ', 'The private key to use for deployment', PRIVATE_KEY) .option( '-m, --mnemonic ', 'The mnemonic to use in deployment', @@ -49,7 +49,7 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: DebugL ETHEREUM_HOST, ) .addOption(pxeOption) - .requiredOption('-p, --private-key ', 'The private key to use for deployment', PRIVATE_KEY) + .requiredOption('-pk, --private-key ', 'The private key to use for deployment', PRIVATE_KEY) .option( '-m, --mnemonic ', 'The mnemonic to use in deployment', diff --git a/yarn-project/cli/src/cmds/utils/deploy_contracts.ts b/yarn-project/cli/src/cmds/utils/deploy_contracts.ts new file mode 100644 index 000000000000..367e0740504a --- /dev/null +++ b/yarn-project/cli/src/cmds/utils/deploy_contracts.ts @@ -0,0 +1,136 @@ +import { DefaultWaitOpts, type EthAddress, NoFeePaymentMethod, type Wallet } from '@aztec/aztec.js'; +import { + AztecAddress, + CANONICAL_AUTH_REGISTRY_ADDRESS, + CANONICAL_KEY_REGISTRY_ADDRESS, + GasSettings, + MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS, +} from '@aztec/circuits.js'; +import { bufferAsFields } from '@aztec/foundation/abi'; +import { type LogFn } from '@aztec/foundation/log'; +import { getCanonicalAuthRegistry } from '@aztec/protocol-contracts/auth-registry'; +import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token'; +import { getCanonicalKeyRegistry } from '@aztec/protocol-contracts/key-registry'; + +/** + * Deploys the contract to pay for gas on L2. + */ +export async function deployCanonicalL2GasToken( + deployer: Wallet, + gasPortalAddress: EthAddress, + log: LogFn, + waitOpts = DefaultWaitOpts, +) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore - Importing noir-contracts.js even in devDeps results in a circular dependency error. Need to ignore because this line doesn't cause an error in a dev environment + const { GasTokenContract } = await import('@aztec/noir-contracts.js'); + + const canonicalGasToken = getCanonicalGasToken(); + + if (await deployer.isContractClassPubliclyRegistered(canonicalGasToken.contractClass.id)) { + log(`Gas Token contract class already registered with id ${canonicalGasToken.contractClass.id}`); + return; + } + + const publicBytecode = canonicalGasToken.contractClass.packedBytecode; + const encodedBytecode = bufferAsFields(publicBytecode, MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS); + await deployer.addCapsule(encodedBytecode); + const gasToken = await GasTokenContract.at(canonicalGasToken.address, deployer); + await gasToken.methods + .deploy( + canonicalGasToken.contractClass.artifactHash, + canonicalGasToken.contractClass.privateFunctionsRoot, + canonicalGasToken.contractClass.publicBytecodeCommitment, + gasPortalAddress, + ) + .send({ fee: { paymentMethod: new NoFeePaymentMethod(), gasSettings: GasSettings.teardownless() } }) + .wait(waitOpts); + + if (!gasToken.address.equals(canonicalGasToken.address)) { + throw new Error( + `Deployed Gas Token address ${gasToken.address} does not match expected address ${canonicalGasToken.address}`, + ); + } + + if (!(await deployer.isContractPubliclyDeployed(canonicalGasToken.address))) { + throw new Error(`Failed to deploy Gas Token to ${canonicalGasToken.address}`); + } + + log(`Deployed Gas Token on L2 at ${canonicalGasToken.address}`); +} + +/** + * Deploys the key registry on L2. + */ +export async function deployCanonicalKeyRegistry(deployer: Wallet, log: LogFn, waitOpts = DefaultWaitOpts) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore - Importing noir-contracts.js even in devDeps results in a circular dependency error. Need to ignore because this line doesn't cause an error in a dev environment + const { KeyRegistryContract } = await import('@aztec/noir-contracts.js'); + + const canonicalKeyRegistry = getCanonicalKeyRegistry(); + + // We check to see if there exists a contract at the canonical Key Registry address with the same contract class id as we expect. This means that + // the key registry has already been deployed to the correct address. + if ( + (await deployer.getContractInstance(canonicalKeyRegistry.address))?.contractClassId.equals( + canonicalKeyRegistry.contractClass.id, + ) && + (await deployer.isContractClassPubliclyRegistered(canonicalKeyRegistry.contractClass.id)) + ) { + log(`Key Registry already deployed at ${canonicalKeyRegistry.address}`); + return; + } + + const keyRegistry = await KeyRegistryContract.deploy(deployer) + .send({ contractAddressSalt: canonicalKeyRegistry.instance.salt, universalDeploy: true }) + .deployed(waitOpts); + + if ( + !keyRegistry.address.equals(canonicalKeyRegistry.address) || + !keyRegistry.address.equals(AztecAddress.fromBigInt(CANONICAL_KEY_REGISTRY_ADDRESS)) + ) { + throw new Error( + `Deployed Key Registry address ${keyRegistry.address} does not match expected address ${canonicalKeyRegistry.address}, or they both do not equal CANONICAL_KEY_REGISTRY_ADDRESS`, + ); + } + + log(`Deployed Key Registry on L2 at ${canonicalKeyRegistry.address}`); +} + +/** + * Deploys the auth registry on L2. + */ +export async function deployCanonicalAuthRegistry(deployer: Wallet, log: LogFn, waitOpts = DefaultWaitOpts) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore - Importing noir-contracts.js even in devDeps results in a circular dependency error. Need to ignore because this line doesn't cause an error in a dev environment + const { AuthRegistryContract } = await import('@aztec/noir-contracts.js'); + + const canonicalAuthRegistry = getCanonicalAuthRegistry(); + + // We check to see if there exists a contract at the canonical Auth Registry address with the same contract class id as we expect. This means that + // the auth registry has already been deployed to the correct address. + if ( + (await deployer.getContractInstance(canonicalAuthRegistry.address))?.contractClassId.equals( + canonicalAuthRegistry.contractClass.id, + ) && + (await deployer.isContractClassPubliclyRegistered(canonicalAuthRegistry.contractClass.id)) + ) { + log(`Auth Registry already deployed at ${canonicalAuthRegistry.address}`); + return; + } + + const authRegistry = await AuthRegistryContract.deploy(deployer) + .send({ contractAddressSalt: canonicalAuthRegistry.instance.salt, universalDeploy: true }) + .deployed(waitOpts); + + if ( + !authRegistry.address.equals(canonicalAuthRegistry.address) || + !authRegistry.address.equals(AztecAddress.fromBigInt(CANONICAL_AUTH_REGISTRY_ADDRESS)) + ) { + throw new Error( + `Deployed Auth Registry address ${authRegistry.address} does not match expected address ${canonicalAuthRegistry.address}, or they both do not equal CANONICAL_AUTH_REGISTRY_ADDRESS`, + ); + } + + log(`Deployed Auth Registry on L2 at ${canonicalAuthRegistry.address}`); +} diff --git a/yarn-project/cli/src/cmds/utils/index.ts b/yarn-project/cli/src/cmds/utils/index.ts index 55b90bfd9272..6ccc824f8459 100644 --- a/yarn-project/cli/src/cmds/utils/index.ts +++ b/yarn-project/cli/src/cmds/utils/index.ts @@ -2,6 +2,8 @@ import { type LogFn } from '@aztec/foundation/log'; import { type Command } from 'commander'; +export * from './deploy_contracts.js'; + export function injectCommands(program: Command, log: LogFn) { program .command('generate-keys') diff --git a/yarn-project/cli/src/utils/commands.ts b/yarn-project/cli/src/utils/commands.ts index d6ca89794199..d51c79f4fcb7 100644 --- a/yarn-project/cli/src/utils/commands.ts +++ b/yarn-project/cli/src/utils/commands.ts @@ -46,7 +46,7 @@ export const l1ChainIdOption = new Option('-c, --l1-chain-id ', 'Chain I }); export const createPrivateKeyOption = (description: string, mandatory: boolean) => - new Option('-e, --private-key ', description) + new Option('-pk, --private-key ', description) .env('PRIVATE_KEY') .argParser(parsePrivateKey) .makeOptionMandatory(mandatory);