diff --git a/contracts/.gitignore b/contracts/.gitignore index 704b55a4..d54786c5 100644 --- a/contracts/.gitignore +++ b/contracts/.gitignore @@ -9,6 +9,10 @@ out/ /broadcast/*/31337/ /broadcast/**/dry-run/ +# Ignores development deployments +contracts/config/anvil_localnet/ +*.tmp.log + # Docs docs/ diff --git a/contracts/README.md b/contracts/README.md index 6594d2ce..60407b52 100644 --- a/contracts/README.md +++ b/contracts/README.md @@ -108,5 +108,5 @@ The scripts output the deployment and upgrade in the `output` folder. - Deploy with `forge create`: ```shell -forge create --broadcast --legacy --json --rpc-url $DOCKER_RPC_URL --private-key $PRIVATE_KEY "src/Nodes.sol:Nodes" +forge create --broadcast --legacy --json --rpc-url $RPC_URL --private-key $PRIVATE_KEY "src/Nodes.sol:Nodes" ``` diff --git a/contracts/config/anvil_localnet/GroupMessages.json b/contracts/config/anvil_localnet/GroupMessages.json index 68741da0..0218c821 100644 --- a/contracts/config/anvil_localnet/GroupMessages.json +++ b/contracts/config/anvil_localnet/GroupMessages.json @@ -1,10 +1,10 @@ { "addresses": { "groupMessagesDeployer": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "groupMessagesImpl": "0xE72B348bCA4DAAD3d8886342557d581B50Bf3971", - "groupMessagesProxy": "0x21A21fa613917600e9dDE4441920562bB6238DaE", + "groupMessagesImpl": "0xf8EE3BDE4408258b5f47316c6006FC08621E20Bb", + "groupMessagesProxy": "0x658DC7259527383eCA195EA2D64F96eA0A13107A", "groupMessagesProxyAdmin": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" }, - "deploymentBlock": 639, - "latestUpgradeBlock": 639 + "deploymentBlock": 768, + "latestUpgradeBlock": 768 } \ No newline at end of file diff --git a/contracts/config/anvil_localnet/IdentityUpdates.json b/contracts/config/anvil_localnet/IdentityUpdates.json index 9805dedb..e72f4db2 100644 --- a/contracts/config/anvil_localnet/IdentityUpdates.json +++ b/contracts/config/anvil_localnet/IdentityUpdates.json @@ -1,10 +1,10 @@ { "addresses": { "identityUpdatesDeployer": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "identityUpdatesImpl": "0x3eEAEf0dddbda233651dc839591b992795Ba7168", - "identityUpdatesProxy": "0x346422cF9c620668089453838EDD1a30F9b1A273", + "identityUpdatesImpl": "0xd26c7386260388BdB17f8114741d9aEDB25d7417", + "identityUpdatesProxy": "0xcE71367f311BC4cD3460b8Bfd0Bd66A19C0837D1", "identityUpdatesProxyAdmin": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" }, - "deploymentBlock": 641, - "latestUpgradeBlock": 641 + "deploymentBlock": 770, + "latestUpgradeBlock": 770 } \ No newline at end of file diff --git a/contracts/dev/deploy-local b/contracts/dev/deploy-local index f3fa8b5e..0cee8ad0 100755 --- a/contracts/dev/deploy-local +++ b/contracts/dev/deploy-local @@ -1,58 +1,32 @@ #!/bin/bash -# Deploy the smart contracts to the local anvil node set -euo pipefail -# Make sure the build directory exists -mkdir -p ./build +############################################ +# Work always from the contracts directory # +############################################ +export source_dir="${SOURCE_DIR:-src}" +export build_dir="${BUILD_DIR:-build}" +export output_dir="${OUTPUT_DIR:-pkg}" +export localnet_dir="${LOCALNET_DIR:-config/anvil_localnet}" -# Always work from the contracts directory script_dir=$(dirname "$(realpath "$0")") repo_root=$(realpath "${script_dir}/../") cd "${repo_root}" +mkdir -p "${build_dir}" \ + "${output_dir}" \ + "${localnet_dir}" + source dev/lib/env source dev/lib/common -echo -e "⧖ Cleaning old artifacts" -forge clean &> forge_clean.log -if [ $? -ne 0 ]; then - echo "ERROR: Failed to clean old artifacts" - cat forge_clean.log - exit 1 -fi -rm forge_clean.log -echo -e "✔ Old artifacts cleaned successfully\n" - -echo -e "⧖ Updating dependencies" -forge soldeer update &> forge_soldeer_update.log -if [ $? -ne 0 ]; then - echo "ERROR: Failed to update dependencies" - cat forge_soldeer_update.log - exit 1 -fi -rm forge_soldeer_update.log -echo -e "✔ Dependencies updated successfully\n" - -echo -e "⧖ Building contracts" -forge build &> forge_build.log -if [ $? -ne 0 ]; then - echo "ERROR: Failed to build contracts" - cat forge_build.log - exit 1 -fi -rm forge_build.log -echo -e "✔ Contracts built successfully\n" - -echo -e "⧖ Running contract tests" -forge test &> forge_test.log -if [ $? -ne 0 ]; then - echo "ERROR: Tests failed" - cat forge_test.log - exit 1 -fi -rm forge_test.log -echo -e "✔ Tests passed successfully\n" - +############################################ +# Deploy the smart contracts to ${RPC_URL} # +############################################ +forge_clean +forge_soldeer_update +forge_build_contracts +forge_test_contracts forge_deploy_script group_messages forge_deploy_script identity_updates forge_deploy_script nodes src/Nodes.sol Nodes diff --git a/contracts/dev/generate b/contracts/dev/generate index b8b9d58d..b3008f5c 100755 --- a/contracts/dev/generate +++ b/contracts/dev/generate @@ -1,18 +1,19 @@ #!/bin/bash - set -euo pipefail -# Default directories (can be overridden with environment variables) -source_dir="${SOURCE_DIR:-src}" -build_dir="${BUILD_DIR:-build}" -output_dir="${OUTPUT_DIR:-pkg}" +############################################ +# Work always from the contracts directory # +############################################ +export source_dir="${SOURCE_DIR:-src}" +export build_dir="${BUILD_DIR:-build}" +export output_dir="${OUTPUT_DIR:-pkg}" -# Ensure required directories exist and clean up old artifacts -function setup_directories() { - mkdir -p "${build_dir}" "${output_dir}" -} +script_dir=$(dirname "$(realpath "$0")") +repo_root=$(realpath "${script_dir}/../") +cd "${repo_root}" + +mkdir -p "${build_dir}" "${output_dir}" -# Generate bindings for a given contract function generate_bindings() { local filename="$1" local package="$(echo "${filename}" | tr '[:upper:]' '[:lower:]')" @@ -47,13 +48,6 @@ function generate_bindings() { } function main() { - # Always work from the contracts directory - script_dir=$(dirname "$(realpath "$0")") - repo_root=$(realpath "${script_dir}/../") - cd "${repo_root}" - - setup_directories - # Define contracts (pass as arguments or use a default list) local contracts=("$@") if [ "${#contracts[@]}" -eq 0 ]; then @@ -65,7 +59,15 @@ function main() { echo "⧖ Generating ABIs for contract: ${contract}" generate_bindings "${contract}" done - echo -e "✔ ABIs generated successfully!\n" + echo -e "\033[32m✔\033[0m ABIs generated successfully!\n" } +################################################# +# Generate the smart contracts bindings for Go # +################################################# +source dev/lib/env +source dev/lib/common + +forge_clean +forge_soldeer_update main "$@" diff --git a/contracts/dev/lib/common b/contracts/dev/lib/common index 48ab39d8..c1abe9e6 100644 --- a/contracts/dev/lib/common +++ b/contracts/dev/lib/common @@ -1,40 +1,103 @@ #!/bin/bash set -euo pipefail +function get_chain_id() { + hex_chain_id=$(curl -s -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_chainId","id":1}' ${RPC_URL} | jq -r '.result') + export chain_id=$((hex_chain_id)) +} + function forge_deploy_script() { + get_chain_id case $1 in group_messages) - echo "⧖ Deploying GroupMessages contract" - forge script --quiet --rpc-url "${DOCKER_RPC_URL}" --broadcast script/DeployGroupMessages.s.sol + echo "⧖ Deploying GroupMessages to chainId ${chain_id} using RPC ${RPC_URL}" + forge script --quiet --rpc-url "${RPC_URL}" --broadcast script/DeployGroupMessages.s.sol if [ $? -ne 0 ]; then echo "Failed to deploy group messages contract" exit 1 fi - echo -e "✔ GroupMessages contract deployed. Deployment details in contracts/config/anvil_localnet/GroupMessages.json\n" + echo -e "\033[32m✔\033[0m GroupMessages deployed. Deployment details in contracts/config/anvil_localnet/GroupMessages.json\n" ;; identity_updates) - echo "⧖ Deploying IdentityUpdates contract" - forge script --quiet --rpc-url "${DOCKER_RPC_URL}" --broadcast script/DeployIdentityUpdates.s.sol + echo "⧖ Deploying IdentityUpdates to chainId ${chain_id} using RPC ${RPC_URL}" + forge script --quiet --rpc-url "${RPC_URL}" --broadcast script/DeployIdentityUpdates.s.sol if [ $? -ne 0 ]; then echo "Failed to deploy identity updates contract" exit 1 fi - echo -e "✔ IdentityUpdates contract deployed. Deployment details in contracts/config/anvil_localnet/IdentityUpdates.json\n" + echo -e "\033[32m✔\033[0m IdentityUpdates deployed. Deployment details in contracts/config/anvil_localnet/IdentityUpdates.json\n" ;; nodes) # TODO: Migrate to forge script - echo "⧖ Deploying Nodes contract" - forge create --broadcast --legacy --json --rpc-url $DOCKER_RPC_URL --private-key $PRIVATE_KEY "$2:$3" > ../build/$3.json - echo -e "✔ Nodes contract deployed. Deployment details in contracts/config/anvil_localnet/$3.json\n" + echo "⧖ Deploying Nodes to chainId ${chain_id} using RPC ${RPC_URL}" + forge create --broadcast --legacy --json --rpc-url $RPC_URL --private-key $PRIVATE_KEY "$2:$3" > build/$3.json + echo -e "\033[32m✔\033[0m Nodes deployed. Deployment details in contracts/build/$3.json\n" ;; *) - echo "Invalid option. Use 'group_messages' or 'identity_updates'." + echo "Invalid option. Use 'group_messages', 'identity_updates' or 'nodes'." exit 1 ;; esac } + +function forge_clean() { + echo -e "⧖ Cleaning old artifacts" + + forge clean &> .forge_clean.tmp.log + if [ $? -ne 0 ]; then + echo "ERROR: Failed to clean old artifacts" + cat .forge_clean.tmp.log + exit 1 + fi + rm .forge_clean.tmp.log + + echo -e "\033[32m✔\033[0m Old artifacts cleaned successfully\n" +} + +function forge_soldeer_update() { + echo -e "⧖ Updating dependencies" + + forge soldeer update &> .forge_soldeer_update.tmp.log + if [ $? -ne 0 ]; then + echo "ERROR: Failed to update dependencies" + cat .forge_soldeer_update.tmp.log + exit 1 + fi + rm .forge_soldeer_update.tmp.log + + echo -e "\033[32m✔\033[0m Dependencies updated successfully\n" +} + +function forge_build_contracts() { + echo -e "⧖ Building contracts" + + forge build &> .forge_build.tmp.log + if [ $? -ne 0 ]; then + echo "ERROR: Failed to build contracts" + cat .forge_build.tmp.log + exit 1 + fi + rm .forge_build.tmp.log + + echo -e "\033[32m✔\033[0m Contracts built successfully\n" +} + +function forge_test_contracts() { + echo -e "⧖ Running contract tests" + + forge test &> .forge_test.tmp.log + if [ $? -ne 0 ]; then + echo "ERROR: Tests failed" + cat .forge_test.tmp.log + exit 1 + fi + rm .forge_test.tmp.log + + echo -e "\033[32m✔\033[0m Tests passed successfully\n" +} + diff --git a/contracts/dev/lib/env b/contracts/dev/lib/env index 226c91d8..bee1d2a5 100644 --- a/contracts/dev/lib/env +++ b/contracts/dev/lib/env @@ -1,6 +1,7 @@ # This is the first default private key for anvil. Nothing sensitive here. export PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 -export DOCKER_RPC_URL=http://localhost:7545 +export RPC_URL=http://localhost:7545 +export VERIFIER_URL= ### XMTP deployment configuration ### # This is the address derivated from the private key above. Not sensitive. diff --git a/dev/local.env b/dev/local.env index 38521690..503eb8a3 100755 --- a/dev/local.env +++ b/dev/local.env @@ -9,12 +9,12 @@ ANVIL_SCRIPTS_OUTPUT=contracts/config/anvil_localnet export XMTPD_DB_WRITER_CONNECTION_STRING="postgres://postgres:xmtp@localhost:8765/postgres?sslmode=disable" # Contract Options -export XMTPD_CONTRACTS_RPC_URL=$DOCKER_RPC_URL # From contracts/.env -XMTPD_CONTRACTS_NODES_ADDRESS="$(jq -r '.deployedTo' build/Nodes.json)" # Built by contracts/deploy-local - TODO: move deployment to forge script +export XMTPD_CONTRACTS_RPC_URL=$RPC_URL # From contracts/dev/lib/env +XMTPD_CONTRACTS_NODES_ADDRESS="$(jq -r '.deployedTo' build/Nodes.json)" # Built by contracts/dev/deploy-local - TODO: move deployment to forge script export XMTPD_CONTRACTS_NODES_ADDRESS -XMTPD_CONTRACTS_MESSAGES_ADDRESS="$(jq -r '.addresses.groupMessagesProxy' ${ANVIL_SCRIPTS_OUTPUT}/GroupMessages.json)" # Built by contracts/deploy-local +XMTPD_CONTRACTS_MESSAGES_ADDRESS="$(jq -r '.addresses.groupMessagesProxy' ${ANVIL_SCRIPTS_OUTPUT}/GroupMessages.json)" # Built by contracts/dev/deploy-local export XMTPD_CONTRACTS_MESSAGES_ADDRESS -XMTPD_CONTRACTS_IDENTITY_UPDATES_ADDRESS="$(jq -r '.addresses.identityUpdatesProxy' ${ANVIL_SCRIPTS_OUTPUT}/IdentityUpdates.json)" # Built by contracts/deploy-local +XMTPD_CONTRACTS_IDENTITY_UPDATES_ADDRESS="$(jq -r '.addresses.identityUpdatesProxy' ${ANVIL_SCRIPTS_OUTPUT}/IdentityUpdates.json)" # Built by contracts/dev/deploy-local export XMTPD_CONTRACTS_IDENTITY_UPDATES_ADDRESS export ANVIL_ACC_1_PRIVATE_KEY="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" diff --git a/dev/up b/dev/up index b08f9c06..55c46042 100755 --- a/dev/up +++ b/dev/up @@ -1,9 +1,6 @@ #!/bin/bash set -e -go mod tidy -git submodule update --init --recursive - if ! which forge &>/dev/null; then echo "ERROR: Missing foundry binaries. Run 'curl -L https://foundry.paradigm.xyz | bash' and follow the instructions" && exit 1; fi if ! which migrate &>/dev/null; then go install github.com/golang-migrate/migrate/v4/cmd/migrate; fi if ! which golangci-lint &>/dev/null; then curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.56.0; fi @@ -25,14 +22,20 @@ if [[ ${abigen_version} != "1.14.12-stable" ]]; then exit 1 fi +echo -e "→ Generate smart contracts bindings" +contracts/dev/generate + +echo -e "→ Update Go dependencies" +go mod tidy + +echo -e "→ Start docker containers" dev/docker/up -# Make sure the abis are updated -contracts/dev/generate +echo -e "→ Deploy smart contracts" contracts/dev/deploy-local -echo -e "⧖ Registering local node-1" +echo -e "→ Register local node-1" dev/register-local-node -echo -e "⧖ Registering local node-2" +echo -e "→ Register local node-2" dev/register-local-node-2