diff --git a/.codecov.yml b/.codecov.yml
index 0cafdec118..ef29efa7b2 100644
--- a/.codecov.yml
+++ b/.codecov.yml
@@ -16,6 +16,8 @@ coverage:
# from go.work file
flags:
+ # note: go.work flags should be in order of the directory structure
+ # also, if you're using multiple module names, you're doing something wrong
agents:
paths:
- agents/
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000000..54f41a6fb7
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,5 @@
+.github
+.vscode
+
+node_modules
+**/node_modules
diff --git a/.github/workflows/goreleaser-actions.yml b/.github/workflows/goreleaser-actions.yml
index 816e2125b4..2fd6654068 100644
--- a/.github/workflows/goreleaser-actions.yml
+++ b/.github/workflows/goreleaser-actions.yml
@@ -75,6 +75,9 @@ jobs:
push: true
file: ./docker/goreleaser/Dockerfile
# TODO this needs to be versioned
+ # Note: this automatically pushes the latest tag for sanguine-goreleaser even on branched workflows. While unlikely,
+ # this could break local devnets that rely on working versions of this image and as such the latest tag should only be pushed on master
+ # additionally, tags representing a specific version rather than the hash of the file should be considered for future use.
tags: ghcr.io/synapsecns/sanguine-goreleaser:latest,${{ steps.name-export.outputs.TAG_NAME }}
cache-from: type=registry,ref=ghcr.io/synapsecns/sanguine-goreleaser:buildcache
cache-to: type=registry,ref=ghcr.io/synapsecns/sanguine-goreleaser:buildcache,mode=max
diff --git a/.gitignore b/.gitignore
index 6f491f2f7f..5bac521f7e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -123,6 +123,8 @@ codecov/
# fasthttp
fastcache.tmp*
+#vercel
+
# ignore all go built files in local dirs
main
-**/.vercel
+.devnet/
diff --git a/.gitmodules b/.gitmodules
index 2f3ff51679..31f95bf224 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -11,3 +11,6 @@
[submodule "services/cctp-relayer/external/synapse-contracts"]
path = services/cctp-relayer/external/synapse-contracts
url = https://github.com/synapsecns/synapse-contracts
+[submodule "packages/contracts-core/lib/create3-factory"]
+ path = packages/contracts-core/lib/create3-factory
+ url = https://github.com/zeframlou/create3-factory
diff --git a/README.md b/README.md
index edecbded3a..e7b5f5b2b7 100644
--- a/README.md
+++ b/README.md
@@ -111,3 +111,10 @@ Use the above commands to recompile the packages.
## Dealing with submodules
This repo make use of [multiple](.gitattributes) [submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules). To avoid issues when checking out different branches, you can use `git submodule update --init --recursive` after switching to a branch or `git checkout feat/branch-name --recurse-submodules` when switching branches.
+
+# Building Agents Locally
+
+
+
+
+In order to minimize risks coming from extraneous dependencies or supply chain attacks in a production like enviornment, all distributed images are built as [scratch](https://hub.docker.com/_/scratch) or [distroless](https://github.com/GoogleContainerTools/distroless#distroless-container-images) images. Builder containers are also not used to restrict the build enviornment to the [goreleaser container](https://github.com/synapsecns/sanguine/pkgs/container/sanguine-goreleaser). All production images are kept in the `docker/` file as `[dir].Dockerfile`. Local
diff --git a/docker/devnet/README.md b/docker/devnet/README.md
new file mode 100644
index 0000000000..ce262082b3
--- /dev/null
+++ b/docker/devnet/README.md
@@ -0,0 +1,21 @@
+Local contains dockerfiles for local development. These files should be able to be built from the root of the repo without any external dependencies.
+
+These don't need to be made for every package, just those involved in devnet.
+
+# Let's keep track of commands here we'll need in our devnet script
+
+1. cd `docker/devnet`
+2. `docker compose build --progress=plain`
+
+## Default Port Map:
+
+| Container | Port |
+|------------------------|------|
+| omnirpc | 9001 |
+| chain_a (chain_id: 42) | 8042 |
+| chain_b (chain_id: 43) | 8043 |
+| chain_c (chain_id: 44) | 8044 |
+| scribe | 9002 |
+
+
+
diff --git a/docker/devnet/agents.Dockerfile b/docker/devnet/agents.Dockerfile
new file mode 100644
index 0000000000..f348f4efed
--- /dev/null
+++ b/docker/devnet/agents.Dockerfile
@@ -0,0 +1,26 @@
+FROM ghcr.io/synapsecns/sanguine-goreleaser:latest as builder
+
+ARG VERSION=v0.0.0
+
+COPY ./services /app/services
+COPY ./agents /app/agents
+COPY ./core /app/core
+COPY ./ethergo /app/ethergo
+COPY ./tools /app/tools
+COPY ./contrib /app/contrib
+COPY ./go.work /app/go.work
+COPY ./go.work.sum /app/go.work.sum
+COPY ./.git /app/.git
+
+WORKDIR /app/agents
+
+RUN --mount=type=cache,target=/root/go/pkg/mod GOPROXY=https://proxy.golang.org go mod download -x
+RUN --mount=type=cache,target=/root/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build CC=gcc CXX=g++ go build -tags=netgo,osusergo -ldflags="-s -w -extldflags '-static'" -o /app/bin/agents main.go
+
+FROM ubuntu:20.04
+
+RUN apt update && apt install -y bash sqlite3 ca-certificates htop
+RUN update-ca-certificates
+COPY --from=builder /app/bin/agents /usr/local/bin
+
+CMD ["agents"]
diff --git a/docker/devnet/config/executor-config.yml b/docker/devnet/config/executor-config.yml
new file mode 100644
index 0000000000..fcea0b49c0
--- /dev/null
+++ b/docker/devnet/config/executor-config.yml
@@ -0,0 +1,53 @@
+# The `db_config` field specifies the database type and the source (either a path or a connection string).
+db_config:
+ # Must be mysql or sqlite.
+ type: sqlite
+ # Source is either a path (for sqlite) or a connection string (for mysql).
+ source: '/config/synapse.db'
+
+# The base omnirpc url which each chain's collection of RPC's will be proxied through.
+base_omnirpc_url: http://omnirpc:9001
+execute_interval: 5
+summit_chain_id: 42
+summit_address: 0x1EC96ab1Fdb92565A0839b12d42c13c8135f6c11
+inbox_address: 0x2eB68A0C21413aA78055F6F7F262De56979aFBEa
+
+# For each chain (including the Summit chain), specify the origin and destination addresses.
+# For remote chains, also specify the light inbox address.
+chains:
+ - chain_id: 42
+ origin_address: 0xD755a6D98C4557c66ebbD9D76f1BEbC48e84afa0
+ destination_address: 0x7219284B26F44B2A584827034422a33450635f7A
+ - chain_id: 43
+ origin_address: 0xD755a6D98C4557c66ebbD9D76f1BEbC48e84afa0
+ destination_address: 0x7219284B26F44B2A584827034422a33450635f7A
+ light_inbox_address: 0xa6A694d8D2430964DcD11f2E649649Fc9557a56b
+ - chain_id: 44
+ origin_address: 0xD755a6D98C4557c66ebbD9D76f1BEbC48e84afa0
+ destination_address: 0x7219284B26F44B2A584827034422a33450635f7A
+ light_inbox_address: 0xa6A694d8D2430964DcD11f2E649649Fc9557a56b
+
+# The `unbonded_signer` field specifies the path to the file containing the private key of the signer
+unbonded_signer:
+ type: 'File'
+ file: '/config/executor-signer.txt'
+
+submitter_config:
+ chains:
+ 42:
+ supports_eip_1559: true
+ gas_estimate: 7500000
+ 43:
+ gas_bump_percentage: 40
+ is_l2: true
+ gas_estimate: 7500000
+ 44:
+ gas_bump_percentage: 40
+ is_l2: true
+ gas_estimate: 7500000
+
+scribe_config:
+ type: 'remote'
+ port: 9002
+ url: 'scribe'
+
diff --git a/docker/devnet/config/executor-signer.txt b/docker/devnet/config/executor-signer.txt
new file mode 100644
index 0000000000..1102cbd038
--- /dev/null
+++ b/docker/devnet/config/executor-signer.txt
@@ -0,0 +1 @@
+103a9ef39d4ced2988f1d5084460ebf8ea3baea2b2ca78265b637e48d99dce82
diff --git a/docker/devnet/config/guard-bonded-signer.txt b/docker/devnet/config/guard-bonded-signer.txt
new file mode 100644
index 0000000000..73cd6db892
--- /dev/null
+++ b/docker/devnet/config/guard-bonded-signer.txt
@@ -0,0 +1 @@
+b31048b0aa87649bdb9016c0ee28c788ddfc45e52cd71cc0da08c47cb4390ae7
diff --git a/docker/devnet/config/guard-config.yml b/docker/devnet/config/guard-config.yml
new file mode 100644
index 0000000000..8f7d5047b7
--- /dev/null
+++ b/docker/devnet/config/guard-config.yml
@@ -0,0 +1,66 @@
+# The `db_config` field specifies the database type and the source (either a path or a connection string).
+db_config:
+ # Must be mysql or sqlite.
+ type: sqlite
+ # Source is either a path (for sqlite) or a connection string (for mysql).
+ source: '/data/synapse.db'
+
+# The base omnirpc url which each chain's collection of RPC's will be proxied through.
+base_omnirpc_url: http://omnirpc:9001
+refresh_interval_seconds: 5
+
+# For each chain (domain), specify the necessary contracts. ***** TODO: Update this *****
+domains:
+ domain_client1:
+ domain_id: 43
+ type: EVM
+ required_confirmations: 0
+ origin_address: 0xD755a6D98C4557c66ebbD9D76f1BEbC48e84afa0
+ domain_client2:
+ domain_id: 42
+ type: EVM
+ required_confirmations: 0
+ origin_address: 0xD755a6D98C4557c66ebbD9D76f1BEbC48e84afa0
+ summit_address: 0x1EC96ab1Fdb92565A0839b12d42c13c8135f6c11
+ inbox_address: 0x2eB68A0C21413aA78055F6F7F262De56979aFBEa
+ domain_client3:
+ domain_id: 44
+ type: EVM
+ required_confirmations: 0
+ origin_address: 0xD755a6D98C4557c66ebbD9D76f1BEbC48e84afa0
+
+# Specify the summit domain id
+summit_domain_id: 42
+# Guards have a `domain_id` of 0.
+domain_id: 0
+
+# The `unbonded_signer` field specifies the path to the file containing the private key of the signer
+unbonded_signer:
+ type: 'File'
+ file: '/config/guard-bonded-signer.txt'
+
+# The `bonded_signer` is the account that will post a bond to the Summit contract. Specify its path to
+# the file containing the private key of the signer
+bonded_signer:
+ type: 'File'
+ file: '/config/guard-bonded-signer.txt'
+
+# The `submitter_config` field specifies how the submitter should submit messages to the chains.
+submitter_config:
+ chains:
+ 42:
+ supports_eip_1559: true
+ gas_estimate: 7500000
+ 43:
+ gas_bump_percentage: 40
+ is_l2: true
+ gas_estimate: 7500000
+ 44:
+ gas_bump_percentage: 40
+ is_l2: true
+ gas_estimate: 7500000
+
+scribe_config:
+ type: 'remote'
+ port: 9002
+ url: 'scribe'
diff --git a/docker/devnet/config/notary43-bonded-signer.txt b/docker/devnet/config/notary43-bonded-signer.txt
new file mode 100644
index 0000000000..ab3d6b0c0c
--- /dev/null
+++ b/docker/devnet/config/notary43-bonded-signer.txt
@@ -0,0 +1 @@
+d5c561f92921a5d7eb8a91cc81cb392d1877dcc6b856260c1676cb28ef7203b0
diff --git a/docker/devnet/config/notary43-config.yml b/docker/devnet/config/notary43-config.yml
new file mode 100644
index 0000000000..e49ccb16af
--- /dev/null
+++ b/docker/devnet/config/notary43-config.yml
@@ -0,0 +1,73 @@
+# The `db_config` field specifies the database type and the source (either a path or a connection string).
+db_config:
+ # Must be mysql or sqlite.
+ type: sqlite
+ # Source is either a path (for sqlite) or a connection string (for mysql).
+ source: '/config/synapse.db'
+
+# The base omnirpc url which each chain's collection of RPC's will be proxied through.
+base_omnirpc_url: http://omnirpc:9001
+refresh_interval_seconds: 5
+
+# For each chain (domain), specify the necessary contracts.
+# Remotes need: origin_address, destination_address, light_inbox_address, light_manager_address
+# Summit needs: origin_address, destination_address, summit_address, inbox_address, bonding_manager_address
+domains:
+ domain_client43:
+ domain_id: 43
+ type: EVM
+ required_confirmations: 0
+ origin_address: 0xD755a6D98C4557c66ebbD9D76f1BEbC48e84afa0
+ destination_address: 0x7219284B26F44B2A584827034422a33450635f7A
+ light_inbox_address: 0xa6A694d8D2430964DcD11f2E649649Fc9557a56b
+ light_manager_address: 0x807A8d4469DD803B9b2c9e3568D5E83784bec25D
+ domain_client44:
+ domain_id: 44
+ type: EVM
+ required_confirmations: 0
+ origin_address: 0xD755a6D98C4557c66ebbD9D76f1BEbC48e84afa0
+ destination_address: 0x7219284B26F44B2A584827034422a33450635f7A
+ light_inbox_address: 0xa6A694d8D2430964DcD11f2E649649Fc9557a56b
+ light_manager_address: 0x807A8d4469DD803B9b2c9e3568D5E83784bec25D
+ domain_client42:
+ domain_id: 42
+ type: EVM
+ required_confirmations: 0
+ # for some reason, origin and summit addresses are switched on synchain
+ origin_address: 0xD755a6D98C4557c66ebbD9D76f1BEbC48e84afa0
+ summit_address: 0x1EC96ab1Fdb92565A0839b12d42c13c8135f6c11
+ inbox_address: 0x2eB68A0C21413aA78055F6F7F262De56979aFBEa
+ destination_address: 0x7219284B26F44B2A584827034422a33450635f7A
+ bonding_manager_address: 0x27006519C5786863fAE35612Da9E0f0622ff8c58
+
+
+# Specify the summit domain id
+summit_domain_id: 42
+# A Notary's `domain_id` is the domain id of the chain it has posted a bond for.
+domain_id: 43
+
+# The `unbonded_signer` field specifies the path to the file containing the private key of the signer
+unbonded_signer:
+ type: 'File'
+ file: '/config/notary-bonded-signer.txt'
+
+# The `bonded_signer` is the account that will post a bond to the Summit contract. Specify its path to
+# the file containing the private key of the signer
+bonded_signer:
+ type: 'File'
+ file: '/config/notary-bonded-signer.txt'
+
+# The `submitter_config` field specifies how the submitter should submit messages to the chains.
+submitter_config:
+ chains:
+ 42:
+ supports_eip_1559: true
+ gas_estimate: 7500000
+ 43:
+ gas_bump_percentage: 40
+ is_l2: true
+ gas_estimate: 7500000
+ 44:
+ gas_bump_percentage: 40
+ is_l2: true
+ gas_estimate: 7500000
diff --git a/docker/devnet/config/notary44-bonded-signer.txt b/docker/devnet/config/notary44-bonded-signer.txt
new file mode 100644
index 0000000000..b4cfedc0af
--- /dev/null
+++ b/docker/devnet/config/notary44-bonded-signer.txt
@@ -0,0 +1 @@
+f466f6f4d2d61a11eddd10eb80aae500c7601539d08d1d55f9e5efe25ecf95bc
diff --git a/docker/devnet/config/notary44-config.yml b/docker/devnet/config/notary44-config.yml
new file mode 100644
index 0000000000..9b9c87313a
--- /dev/null
+++ b/docker/devnet/config/notary44-config.yml
@@ -0,0 +1,73 @@
+# The `db_config` field specifies the database type and the source (either a path or a connection string).
+db_config:
+ # Must be mysql or sqlite.
+ type: sqlite
+ # Source is either a path (for sqlite) or a connection string (for mysql).
+ source: '/config/synapse.db'
+
+# The base omnirpc url which each chain's collection of RPC's will be proxied through.
+base_omnirpc_url: http://omnirpc:9001
+refresh_interval_seconds: 5
+
+# For each chain (domain), specify the necessary contracts.
+# Remotes need: origin_address, destination_address, light_inbox_address, light_manager_address
+# Summit needs: origin_address, destination_address, summit_address, inbox_address, bonding_manager_address
+domains:
+ domain_client43:
+ domain_id: 43
+ type: EVM
+ required_confirmations: 0
+ origin_address: 0xD755a6D98C4557c66ebbD9D76f1BEbC48e84afa0
+ destination_address: 0x7219284B26F44B2A584827034422a33450635f7A
+ light_inbox_address: 0xa6A694d8D2430964DcD11f2E649649Fc9557a56b
+ light_manager_address: 0x807A8d4469DD803B9b2c9e3568D5E83784bec25D
+ domain_client44:
+ domain_id: 44
+ type: EVM
+ required_confirmations: 0
+ origin_address: 0xD755a6D98C4557c66ebbD9D76f1BEbC48e84afa0
+ destination_address: 0x7219284B26F44B2A584827034422a33450635f7A
+ light_inbox_address: 0xa6A694d8D2430964DcD11f2E649649Fc9557a56b
+ light_manager_address: 0x807A8d4469DD803B9b2c9e3568D5E83784bec25D
+ domain_client42:
+ domain_id: 42
+ type: EVM
+ required_confirmations: 0
+ # for some reason, origin and summit addresses are switched on synchain
+ origin_address: 0xD755a6D98C4557c66ebbD9D76f1BEbC48e84afa0
+ summit_address: 0x1EC96ab1Fdb92565A0839b12d42c13c8135f6c11
+ inbox_address: 0x2eB68A0C21413aA78055F6F7F262De56979aFBEa
+ destination_address: 0x7219284B26F44B2A584827034422a33450635f7A
+ bonding_manager_address: 0x27006519C5786863fAE35612Da9E0f0622ff8c58
+
+
+# Specify the summit domain id
+summit_domain_id: 42
+# A Notary's `domain_id` is the domain id of the chain it has posted a bond for.
+domain_id: 44
+
+# The `unbonded_signer` field specifies the path to the file containing the private key of the signer
+unbonded_signer:
+ type: 'File'
+ file: '/config/notary-bonded-signer.txt'
+
+# The `bonded_signer` is the account that will post a bond to the Summit contract. Specify its path to
+# the file containing the private key of the signer
+bonded_signer:
+ type: 'File'
+ file: '/config/notary-bonded-signer.txt'
+
+# The `submitter_config` field specifies how the submitter should submit messages to the chains.
+submitter_config:
+ chains:
+ 42:
+ supports_eip_1559: true
+ gas_estimate: 7500000
+ 43:
+ gas_bump_percentage: 40
+ is_l2: true
+ gas_estimate: 7500000
+ 44:
+ gas_bump_percentage: 40
+ is_l2: true
+ gas_estimate: 7500000
diff --git a/docker/devnet/config/omnirpc.yaml b/docker/devnet/config/omnirpc.yaml
new file mode 100644
index 0000000000..7080df1b18
--- /dev/null
+++ b/docker/devnet/config/omnirpc.yaml
@@ -0,0 +1,17 @@
+chains:
+ 42:
+ rpcs:
+ - http://chain_a:8545/
+ confirmations: 1
+ 43:
+ rpcs:
+ - http://chain_b:8545/
+ confirmations: 1
+ 44:
+ rpcs:
+ - http://chain_c:8545/
+ confirmations: 1
+# port to run on
+port: 9001
+# expressed in seconds
+refreshInterval: 60
diff --git a/docker/devnet/config/prometheus/prometheus.yml b/docker/devnet/config/prometheus/prometheus.yml
new file mode 100644
index 0000000000..d4863f95c7
--- /dev/null
+++ b/docker/devnet/config/prometheus/prometheus.yml
@@ -0,0 +1,17 @@
+global:
+ scrape_interval: 10s
+ scrape_timeout: 10s
+
+scrape_configs:
+ - job_name: services
+ metrics_path: /metrics
+ static_configs:
+ - targets:
+ - 'prometheus:9090'
+ - 'scribe-indexer:8080'
+ - 'scribe:8080'
+ - 'omnirpc:8080'
+ - 'notary-43:8080'
+ - 'notary-44:8080'
+ - 'executor:8080'
+
diff --git a/docker/devnet/config/scribe-indexer-config.yaml b/docker/devnet/config/scribe-indexer-config.yaml
new file mode 100644
index 0000000000..6aefac8b38
--- /dev/null
+++ b/docker/devnet/config/scribe-indexer-config.yaml
@@ -0,0 +1,47 @@
+chains:
+ - chain_id: 42
+ required_confirmations: 0
+ contract_sub_chunk_size: 512
+ contract_chunk_size: 512
+ store_concurrency_threshold: 100000
+ contracts:
+ - address: 0xD755a6D98C4557c66ebbD9D76f1BEbC48e84afa0
+ start_block: 1
+ - address: 0x1EC96ab1Fdb92565A0839b12d42c13c8135f6c11
+ start_block: 1
+ - address: 0x2eB68A0C21413aA78055F6F7F262De56979aFBEa
+ start_block: 1
+ - address: 0x7219284B26F44B2A584827034422a33450635f7A
+ start_block: 1
+ - address: 0x27006519C5786863fAE35612Da9E0f0622ff8c58
+ start_block: 1
+ - chain_id: 43
+ required_confirmations: 0
+ contract_sub_chunk_size: 512
+ contract_chunk_size: 512
+ store_concurrency_threshold: 100000
+ contracts:
+ - address: 0xD755a6D98C4557c66ebbD9D76f1BEbC48e84afa0
+ start_block: 1
+ - address: 0x7219284B26F44B2A584827034422a33450635f7A
+ start_block: 1
+ - address: 0xa6A694d8D2430964DcD11f2E649649Fc9557a56b
+ start_block: 1
+ - address: 0x807A8d4469DD803B9b2c9e3568D5E83784bec25D
+ start_block: 1
+ - chain_id: 44
+ required_confirmations: 0
+ contract_sub_chunk_size: 512
+ contract_chunk_size: 512
+ store_concurrency_threshold: 100000
+ contracts:
+ - address: 0xD755a6D98C4557c66ebbD9D76f1BEbC48e84afa0
+ start_block: 1
+ - address: 0x7219284B26F44B2A584827034422a33450635f7A
+ start_block: 1
+ - address: 0xa6A694d8D2430964DcD11f2E649649Fc9557a56b
+ start_block: 1
+ - address: 0x807A8d4469DD803B9b2c9e3568D5E83784bec25D
+ start_block: 1
+rpc_url: 'http://omnirpc:9001/confirmations'
+refresh_rate: 0
diff --git a/docker/devnet/docker-compose.yml b/docker/devnet/docker-compose.yml
new file mode 100644
index 0000000000..26f2056236
--- /dev/null
+++ b/docker/devnet/docker-compose.yml
@@ -0,0 +1,267 @@
+version: '3.4'
+
+# This compose file is expected to be used from make and not independently.
+
+volumes:
+ chain_a_data:
+ chain_b_data:
+ chain_c_data:
+ guard_data:
+ notary43_data:
+ scribe_data:
+ prometheus-data:
+ badger-data:
+ notary44_data:
+ executor_data:
+
+
+services:
+ guard:
+ restart: unless-stopped
+ entrypoint: agents
+ depends_on:
+ - omnirpc
+ - scribe
+ build:
+ context: ../../
+ dockerfile: docker/devnet/agents.Dockerfile
+ volumes:
+ - '${PWD}/config/guard-config.yml:/config/guard-config.yml'
+ - '${PWD}/config/guard-bonded-signer.txt:/config/guard-bonded-signer.txt'
+ - guard_data:/data
+ command:
+ - 'guard-run'
+ - '--config'
+ - '/config/guard-config.yml'
+ environment:
+ METRICS_HANDLER: jaeger
+ JAEGER_ENDPOINT: 'http://tracing:14268/api/traces'
+ GOLOG_LOG_LEVEL: debug
+
+ notary-43:
+ entrypoint: agents
+ restart: unless-stopped
+ depends_on:
+ - omnirpc
+ build:
+ context: ../../
+ dockerfile: docker/devnet/agents.Dockerfile
+ volumes:
+ - '${PWD}/config/notary43-config.yml:/config/notary-config.yml'
+ - '${PWD}/config/notary43-bonded-signer.txt:/config/notary-bonded-signer.txt'
+ - notary43_data:/config/synapse.db
+ command:
+ - 'notary-run'
+ - '--config'
+ - '/config/notary-config.yml'
+ - '--debug'
+ environment:
+ METRICS_HANDLER: jaeger
+ JAEGER_ENDPOINT: 'http://tracing:14268/api/traces'
+ GOLOG_LOG_LEVEL: debug
+
+
+ notary-44:
+ entrypoint: agents
+ restart: unless-stopped
+ depends_on:
+ - omnirpc
+ build:
+ context: ../../
+ dockerfile: docker/devnet/agents.Dockerfile
+ volumes:
+ - '${PWD}/config/notary44-config.yml:/config/notary-config.yml'
+ - '${PWD}/config/notary44-bonded-signer.txt:/config/notary-bonded-signer.txt'
+ - notary44_data:/config/synapse.db
+ command:
+ - 'notary-run'
+ - '--config'
+ - '/config/notary-config.yml'
+ - '--debug'
+ environment:
+ METRICS_HANDLER: jaeger
+ JAEGER_ENDPOINT: 'http://tracing:14268/api/traces'
+ GOLOG_LOG_LEVEL: debug
+
+ executor:
+ entrypoint: agents
+ restart: unless-stopped
+ depends_on:
+ - omnirpc
+ build:
+ context: ../../
+ dockerfile: docker/devnet/agents.Dockerfile
+ volumes:
+ - '${PWD}/config/executor-config.yml:/config/executor-config.yml'
+ - '${PWD}/config/executor-signer.txt:/config/executor-signer.txt'
+ - executor_data:/config/synapse.db
+ command:
+ - 'executor-run'
+ - '--config'
+ - '/config/executor-config.yml'
+ - '--debug'
+ environment:
+ METRICS_HANDLER: jaeger
+ JAEGER_ENDPOINT: 'http://tracing:14268/api/traces'
+ GOLOG_LOG_LEVEL: debug
+
+
+ scribe-indexer:
+ depends_on:
+ - omnirpc
+ build:
+ context: ../../
+ dockerfile: docker/devnet/scribe.Dockerfile
+ entrypoint: scribe
+ restart: unless-stopped
+ command: >
+ scribe
+ --config=/config/scribe.yaml
+ --db=sqlite
+ --path=/data
+ volumes:
+ - '${PWD}/config/scribe-indexer-config.yaml:/config/scribe.yaml'
+ - scribe_data:/data
+ environment:
+ METRICS_HANDLER: jaeger
+ JAEGER_ENDPOINT: 'http://tracing:14268/api/traces'
+ GOLOG_LOG_LEVEL: debug
+
+ scribe:
+ restart: unless-stopped
+ depends_on:
+ - scribe-indexer
+ build:
+ context: ../../
+ dockerfile: docker/devnet/scribe.Dockerfile
+ entrypoint: scribe
+ command: >
+ server
+ --port=9002
+ --db=sqlite
+ --path=/data
+ --omnirpc=http://omnirpc:9001
+ volumes:
+ - scribe_data:/data
+ environment:
+ METRICS_HANDLER: jaeger
+ JAEGER_ENDPOINT: 'http://tracing:14268/api/traces'
+ GOLOG_LOG_LEVEL: debug
+ ports:
+ - '9002:9002'
+
+
+ omnirpc:
+ restart: unless-stopped
+ depends_on:
+ - chain_a
+ - chain_b
+ - chain_c
+ - tracing
+ build:
+ context: ../../
+ dockerfile: docker/devnet/omnirpc.Dockerfile
+ ports:
+ - '9001:9001'
+ command: >
+ omnirpc
+ server
+ --config=/config/omnirpc.yaml
+ volumes:
+ - '${PWD}/config/omnirpc.yaml:/config/omnirpc.yaml'
+ environment:
+ METRICS_HANDLER: jaeger
+ JAEGER_ENDPOINT: 'http://tracing:14268/api/traces'
+# TODO, consider re-enabling.
+# healthcheck:
+# test: ['CMD', 'curl', '-f', 'http://localhost:8545/health']
+# interval: 1s
+# timeout: 20s
+# retries: 10
+# start_period: 5s
+
+ chain_a:
+ restart: unless-stopped
+ image: 'ghcr.io/foundry-rs/foundry:latest'
+ entrypoint: anvil
+ command: >
+ --host=0.0.0.0
+ --chain-id=42
+ --allow-origin='*'
+ --steps-tracing
+ --mnemonic='tag volcano eight thank tide danger coast health above argue embrace heavy'
+ --base-fee=1
+ --gas-limit=100000000
+ --state=/data/
+ ports:
+ - '8042:8545'
+ volumes:
+ - chain_a_data:/data
+
+ chain_b:
+ restart: unless-stopped
+ image: 'ghcr.io/foundry-rs/foundry:latest'
+ entrypoint: anvil
+ command: >
+ --host=0.0.0.0
+ --chain-id=43
+ --allow-origin='*'
+ --steps-tracing
+ --mnemonic='tag volcano eight thank tide danger coast health above argue embrace heavy'
+ --base-fee=1
+ --gas-limit=100000000
+ --state=/data/
+ ports:
+ - '8043:8545'
+ volumes:
+ - chain_b_data:/data
+
+ chain_c:
+ restart: unless-stopped
+ image: 'ghcr.io/foundry-rs/foundry:latest'
+ entrypoint: anvil
+ command: >
+ --host=0.0.0.0
+ --chain-id=44
+ --allow-origin='*'
+ --steps-tracing
+ --mnemonic='tag volcano eight thank tide danger coast health above argue embrace heavy'
+ --base-fee=1
+ --gas-limit=100000000
+ --state=/data/
+ ports:
+ - '8044:8545'
+ volumes:
+ - chain_b_data:/data
+
+ tracing:
+ restart: unless-stopped
+ image: jaegertracing/all-in-one:latest
+ ports:
+ - 6831:6831/udp
+ - 6832:6832/udp
+ - 5778:5778
+ - 16686:16686
+ - 4317:4317
+ - 4318:4318
+ - 14250:14250
+ - 14268:14268
+ - 14269:14269
+ - 9411:9411
+ environment:
+ SPAN_STORAGE_TYPE: 'badger'
+ BADGER_EPHEMERAL: 'false'
+ BADGER_DIRECTORY_VALUE: '/badger/data'
+ BADGER_DIRECTORY_KEY: '/badger/key'
+ volumes:
+ - badger-data:/badger
+
+ prometheus:
+ restart: unless-stopped
+ image: prom/prometheus:v2.46.0
+ ports:
+ - 9000:9090
+ volumes:
+ - '${PWD}/config/prometheus:/etc/prometheus'
+ - prometheus-data:/prometheus
+ command: --web.enable-lifecycle --config.file=/etc/prometheus/prometheus.yml
diff --git a/docker/devnet/omnirpc.Dockerfile b/docker/devnet/omnirpc.Dockerfile
new file mode 100644
index 0000000000..ee218706f6
--- /dev/null
+++ b/docker/devnet/omnirpc.Dockerfile
@@ -0,0 +1,26 @@
+FROM ghcr.io/synapsecns/sanguine-goreleaser:latest as builder
+
+ARG VERSION=v0.0.0
+
+COPY ./services /app/services
+COPY ./agents /app/agents
+COPY ./core /app/core
+COPY ./ethergo /app/ethergo
+COPY ./tools /app/tools
+COPY ./contrib /app/contrib
+COPY ./go.work /app/go.work
+COPY ./go.work.sum /app/go.work.sum
+COPY ./.git /app/.git
+
+WORKDIR /app/services/omnirpc
+
+RUN --mount=type=cache,target=/root/go/pkg/mod GOPROXY=https://proxy.golang.org go mod download -x
+RUN --mount=type=cache,target=/root/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build CC=gcc CXX=g++ go build -tags=netgo,osusergo -ldflags="-s -w -extldflags '-static'" -o /app/bin/omnirpc main.go
+
+FROM ubuntu:20.04
+
+RUN apt update && apt install -y bash ca-certificates htop
+RUN update-ca-certificates
+COPY --from=builder /app/bin/omnirpc /usr/local/bin
+
+CMD ["omnirpc"]
diff --git a/docker/devnet/scribe.Dockerfile b/docker/devnet/scribe.Dockerfile
new file mode 100644
index 0000000000..ae1a97bc66
--- /dev/null
+++ b/docker/devnet/scribe.Dockerfile
@@ -0,0 +1,26 @@
+FROM ghcr.io/synapsecns/sanguine-goreleaser:latest as builder
+
+ARG VERSION=v0.0.0
+
+COPY ./services /app/services
+COPY ./agents /app/agents
+COPY ./core /app/core
+COPY ./ethergo /app/ethergo
+COPY ./tools /app/tools
+COPY ./contrib /app/contrib
+COPY ./go.work /app/go.work
+COPY ./go.work.sum /app/go.work.sum
+COPY ./.git /app/.git
+
+WORKDIR /app/services/scribe
+
+RUN --mount=type=cache,target=/root/go/pkg/mod GOPROXY=https://proxy.golang.org go mod download -x
+RUN --mount=type=cache,target=/root/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build CC=gcc CXX=g++ go build -tags=netgo,osusergo -ldflags="-s -w -extldflags '-static'" -o /app/bin/scribe main.go
+
+FROM ubuntu:20.04
+
+RUN apt update && apt install -y bash sqlite3 ca-certificates htop
+RUN update-ca-certificates
+COPY --from=builder /app/bin/scribe /usr/local/bin
+
+CMD ["scribe"]
diff --git a/make/solidity.Makefile b/make/solidity.Makefile
new file mode 100644
index 0000000000..b6d5ed3199
--- /dev/null
+++ b/make/solidity.Makefile
@@ -0,0 +1,25 @@
+# Note: this file is made to be symlinked to various folders where we use go for builds
+# please use libraries if you wish to add folder-specific make functionality
+
+default: help
+
+# set variables
+GIT_ROOT := $(shell git rev-parse --show-toplevel)
+CURRENT_PATH := $(shell pwd)
+RELPATH := $(shell realpath --relative-to="$(GIT_ROOT)" "$(CURRENT_PATH)")
+
+help: ## This help dialog.
+ @IFS=$$'\n' ; \
+ help_lines=(`fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//'`); \
+ for help_line in $${help_lines[@]}; do \
+ IFS=$$'#' ; \
+ help_split=($$help_line) ; \
+ help_command=`echo $${help_split[0]} | sed -e 's/^ *//' -e 's/ *$$//'` ; \
+ help_info=`echo $${help_split[2]} | sed -e 's/^ *//' -e 's/ *$$//'` ; \
+ printf "%-30s %s\n" $$help_command $$help_info ; \
+ done
+
+# TODO: deployer utils requires jq, install
+
+foundry-install:
+ @if [ "$(shell which forge)" = "" ]; then curl -L https://foundry.paradigm.xyz | bash && foundryup; fi
diff --git a/packages/contracts-core/.example.env b/packages/contracts-core/.example.env
index d27b151ead..bccf0ecfa1 100644
--- a/packages/contracts-core/.example.env
+++ b/packages/contracts-core/.example.env
@@ -6,4 +6,4 @@ RPC_POLYGON=https://polygon.llamarpc.com
ETHERSCAN_AVALANCHE_KEY=
ETHERSCAN_OPTIMISM_KEY=
-ETHERSCAN_POLYGON_KEY=
\ No newline at end of file
+ETHERSCAN_POLYGON_KEY=
diff --git a/packages/contracts-core/Makefile b/packages/contracts-core/Makefile
new file mode 100644
index 0000000000..973a998067
--- /dev/null
+++ b/packages/contracts-core/Makefile
@@ -0,0 +1,32 @@
+include ../../make/solidity.Makefile
+
+devnet-clean: ## Delete all devnet data and docker containers
+ rm -rf deployments/chain_a/*.json
+ rm -rf deployments/chain_b/*.json
+ rm -rf deployments/chain_c/*.json
+
+ # TODO: this should also delete broadcast/**/42, broadcast/**/43, broadcast/**/44
+ rm -rf broadcast/42/*
+ rm -rf broadcast/43/*
+ rm -rf broadcast/44/*
+
+ cd ../../docker/devnet && docker-compose down --volumes
+
+devnet-up: ## This should be run to start the devnet docker-containers. This does not deploy anything.
+ cd ../../docker/devnet && docker-compose up -d --build
+
+devnet-deploy: ## This should be run exactly once to deploy the contracts to the devnet.
+ # backup the .env in case there's real data in there
+ cp .env /tmp/.env.bak || true
+ cp devnet.env .env
+
+ forge script script/DeployMessaging003SynChain.s.sol --ffi -f chain_a --private-key 63e21d10fd50155dbba0e7d3f7431a400b84b4c2ac1ee38872f82448fe3ecfb9 --broadcast
+ forge script script/DeployMessaging003LightChain.s.sol --ffi -f chain_b --private-key 63e21d10fd50155dbba0e7d3f7431a400b84b4c2ac1ee38872f82448fe3ecfb9 --broadcast
+ forge script script/DeployMessaging003LightChain.s.sol --ffi -f chain_c --private-key 63e21d10fd50155dbba0e7d3f7431a400b84b4c2ac1ee38872f82448fe3ecfb9 --broadcast
+
+ forge script script/DeployClients003.s.sol --ffi -f chain_a --private-key 63e21d10fd50155dbba0e7d3f7431a400b84b4c2ac1ee38872f82448fe3ecfb9 --broadcast
+ forge script script/DeployClients003.s.sol --ffi -f chain_b --private-key 63e21d10fd50155dbba0e7d3f7431a400b84b4c2ac1ee38872f82448fe3ecfb9 --broadcast
+ forge script script/DeployClients003.s.sol --ffi -f chain_c --private-key 63e21d10fd50155dbba0e7d3f7431a400b84b4c2ac1ee38872f82448fe3ecfb9 --broadcast
+
+devnet-logs:
+ cd ../../docker/devnet && docker-compose logs -f
diff --git a/packages/contracts-core/README.md b/packages/contracts-core/README.md
index c781183319..efdd8dbd45 100644
--- a/packages/contracts-core/README.md
+++ b/packages/contracts-core/README.md
@@ -39,3 +39,34 @@ root
├── script: Scripts for deploying + interacting with contracts
├── test: Test contracts
+
+
+## Running a devnet
+
+
+
+To run a devnet, you can run `make devnet-up` and `make devnet-deploy` from this directory. This will start a local devnet and deploy the contracts to it. RPC endpoints for debugging etc will be availabe at `http://localhost:9001/rpc/[chain_id]`.
+
+By default, the [`PingPongClient.sol`](contracts/client/PingPongClient.sol) is deployed, so you can interact with it with cast. For instance, to send a ping from chain 42 to chain 44:
+
+```bash
+cast send 0x521F44132489CDD54c9ceC8167CfC377CbAEa351 --rpc-url http://localhost:9001/rpc/42 --private-key 0x526db1890baf94e82162f17f25ad769eb7f981272d8d99c527ea1af443c2d0cc "doPing(uint32,address,uint16)" 44 0x521F44132489CDD54c9ceC8167CfC377CbAEa351 1
+```
+
+Now, to make sure it work, you can pull up [scribe](../../services/scribe/) by going to http://localhost:9002/graphiql and [querying the logs](http://localhost:9002/graphiql?query=%7B%0A%20%20%0A%20%20logs(chain_id%3A%2044%2C%20page%3A%201)%7B%0A%20%20%20%20topics%0A%20%20%20%20receipt%0A%20%20%20%20block_number%0A%20%20%7D%0A%7D) for chain 44:
+
+
+```graphql
+{
+
+ logs(chain_id: 44, page: 1){
+ topics
+ block_number
+ contract_address
+ }
+}
+```
+
+If everything went well, you will see topic `0x0a72872b9cfe43d6c13b13553f28d4879e427f3b456545649fd0761fdcbe0311` in the logs, which is the topic for the `PingPongClient`'s `Pong` event.
+
+![graphql screenshot](./assets/screenshot.png)
diff --git a/packages/contracts-core/assets/screenshot.png b/packages/contracts-core/assets/screenshot.png
new file mode 100644
index 0000000000..c8c776396c
Binary files /dev/null and b/packages/contracts-core/assets/screenshot.png differ
diff --git a/packages/contracts-core/deployments/chain_a/.gitignore b/packages/contracts-core/deployments/chain_a/.gitignore
new file mode 100644
index 0000000000..7dc54a519e
--- /dev/null
+++ b/packages/contracts-core/deployments/chain_a/.gitignore
@@ -0,0 +1,5 @@
+# Ignore everything
+*
+
+# But not this file
+!.gitignore
diff --git a/packages/contracts-core/deployments/chain_b/.gitignore b/packages/contracts-core/deployments/chain_b/.gitignore
new file mode 100644
index 0000000000..7dc54a519e
--- /dev/null
+++ b/packages/contracts-core/deployments/chain_b/.gitignore
@@ -0,0 +1,5 @@
+# Ignore everything
+*
+
+# But not this file
+!.gitignore
diff --git a/packages/contracts-core/deployments/chain_c/.gitignore b/packages/contracts-core/deployments/chain_c/.gitignore
new file mode 100644
index 0000000000..7dc54a519e
--- /dev/null
+++ b/packages/contracts-core/deployments/chain_c/.gitignore
@@ -0,0 +1,5 @@
+# Ignore everything
+*
+
+# But not this file
+!.gitignore
diff --git a/packages/contracts-core/devnet.env b/packages/contracts-core/devnet.env
new file mode 100644
index 0000000000..700cd36ca1
--- /dev/null
+++ b/packages/contracts-core/devnet.env
@@ -0,0 +1,12 @@
+# don't send internet monies here
+MESSAGING_DEPLOYER_PRIVATE_KEY=63e21d10fd50155dbba0e7d3f7431a400b84b4c2ac1ee38872f82448fe3ecfb9
+
+RPC_AVALANCHE=https://api.avax.network/ext/bc/C/rpc
+RPC_OPTIMISM=https://1rpc.io/op
+RPC_POLYGON=https://polygon.llamarpc.com
+
+ETHERSCAN_AVALANCHE_KEY=
+ETHERSCAN_OPTIMISM_KEY=
+ETHERSCAN_POLYGON_KEY=
+
+DEVNET=true
diff --git a/packages/contracts-core/foundry.toml b/packages/contracts-core/foundry.toml
index f6f52240ea..f6be41d854 100644
--- a/packages/contracts-core/foundry.toml
+++ b/packages/contracts-core/foundry.toml
@@ -25,6 +25,11 @@ polygon = "${RPC_POLYGON}"
arb_goerli = "${RPC_ARB_GOERLI}"
op_goerli = "${RPC_OP_GOERLI}"
sepolia = "${RPC_SEPOLIA}"
+# devnet chains
+chain_a = "http://localhost:9001/rpc/42"
+chain_b = "http://localhost:9001/rpc/43"
+chain_c = "http://localhost:9001/rpc/44"
+
[etherscan]
avalanche = { key = "${ETHERSCAN_AVALANCHE_KEY}" }
diff --git a/packages/contracts-core/lib/create3-factory b/packages/contracts-core/lib/create3-factory
new file mode 160000
index 0000000000..06ec0ff36d
--- /dev/null
+++ b/packages/contracts-core/lib/create3-factory
@@ -0,0 +1 @@
+Subproject commit 06ec0ff36d41853dcd4399fbe2127aef801c4077
diff --git a/packages/contracts-core/remappings.txt b/packages/contracts-core/remappings.txt
index 907d6d3d0e..9d6fc62b2c 100644
--- a/packages/contracts-core/remappings.txt
+++ b/packages/contracts-core/remappings.txt
@@ -1,2 +1,3 @@
forge-std=lib/forge-std/src
-ds-test=lib/forge-std/lib/ds-test/src
\ No newline at end of file
+ds-test=lib/forge-std/lib/ds-test/src
+create3=lib/create3-factory/src
diff --git a/packages/contracts-core/script/DeployCREATE3Factory.sol b/packages/contracts-core/script/DeployCREATE3Factory.sol
new file mode 100644
index 0000000000..dc28d11154
--- /dev/null
+++ b/packages/contracts-core/script/DeployCREATE3Factory.sol
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: MIT
+pragma solidity 0.8.17;
+
+import {console, stdJson} from "forge-std/Script.sol";
+import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
+
+// ═════════════════════════════ INTERNAL IMPORTS ══════════════════════════════
+import {DeployerUtils} from "./utils/DeployerUtils.sol";
+
+import {CREATE3Factory} from "create3/CREATE3Factory.sol";
+
+// TODO: move this to a common deployer-utils package, as this is not specific to SIN
+contract DeployCREATE3Factory is DeployerUtils {
+ using stdJson for string;
+ using Strings for uint256;
+
+ constructor() {
+ setupPK("MESSAGING_DEPLOYER_PRIVATE_KEY");
+ setupDevnetIfEnabled();
+ }
+
+ function run() external {
+ startBroadcast(true);
+ CREATE3Factory NewFactory = new CREATE3Factory();
+ saveDeployment("CREATE3", "CREATE3", address(NewFactory), "0x");
+ stopBroadcast();
+ }
+}
diff --git a/packages/contracts-core/script/DeployClients003.s.sol b/packages/contracts-core/script/DeployClients003.s.sol
index 491f8577d6..d8d30e90e5 100644
--- a/packages/contracts-core/script/DeployClients003.s.sol
+++ b/packages/contracts-core/script/DeployClients003.s.sol
@@ -26,6 +26,7 @@ contract DeployClients003Script is DeployerUtils {
constructor() {
setupPK("MESSAGING_DEPLOYER_PRIVATE_KEY");
+ setupDevnetIfEnabled();
}
/// @dev Function to exclude script from coverage report
diff --git a/packages/contracts-core/script/DeployMessaging003Base.s.sol b/packages/contracts-core/script/DeployMessaging003Base.s.sol
index 450c1f8d78..c62018ca59 100644
--- a/packages/contracts-core/script/DeployMessaging003Base.s.sol
+++ b/packages/contracts-core/script/DeployMessaging003Base.s.sol
@@ -47,6 +47,7 @@ abstract contract DeployMessaging003BaseScript is DeployerUtils {
setupPK("MESSAGING_DEPLOYER_PRIVATE_KEY");
localDomain = uint32(block.chainid);
deploymentSalt = keccak256("Messaging003");
+ setupDevnetIfEnabled();
}
/// @dev Function to exclude script from coverage report
@@ -86,6 +87,8 @@ abstract contract DeployMessaging003BaseScript is DeployerUtils {
globalConfig = loadGlobalDeployConfig("Messaging003");
synapseDomain = globalConfig.readUint(".chainidSummit");
startBroadcast(_isBroadcasted);
+ // assert this is the first thing deployed
+ getFactory();
// Predict deployments
agentManager = predictFactoryDeployment(agentManagerName());
statementInbox = predictFactoryDeployment(statementInboxName());
diff --git a/packages/contracts-core/script/SetupGasOracle003.s.sol b/packages/contracts-core/script/SetupGasOracle003.s.sol
index c0dfb44a30..404b50aa44 100644
--- a/packages/contracts-core/script/SetupGasOracle003.s.sol
+++ b/packages/contracts-core/script/SetupGasOracle003.s.sol
@@ -47,6 +47,7 @@ contract SetupGasOracle003Script is DeployerUtils {
/// @dev To simulate setup on $chainName
/// forge script script/SetupGasOracle003.s.sol -f chainName
function run() external {
+ setupDevnetIfEnabled();
startBroadcast(true);
gasDataConfig = loadGlobalDeployConfig("Messaging003GasData");
gasOracle = GasOracle(loadDeployment(GAS_ORACLE));
diff --git a/packages/contracts-core/script/configs/devnet/Messaging003.dc.json b/packages/contracts-core/script/configs/devnet/Messaging003.dc.json
new file mode 100644
index 0000000000..550a797ebf
--- /dev/null
+++ b/packages/contracts-core/script/configs/devnet/Messaging003.dc.json
@@ -0,0 +1,10 @@
+{
+ "agents": {
+ "0": ["0x8230645aC28A4EdD1b0B53E7Cd8019744E9dD559"],
+ "43": ["0x65c150B7eF3B1adbB9cB2b8041C892b15eDde05A"],
+ "44": ["0x1AebbE69459B80d4975259378577Bc01d2924Cf4"]
+ },
+ "chainidSummit": 42,
+ "domains": [0, 43, 44],
+ "owner": "0xC49926C4124cEe1cbA0Ea94Ea31a6c12318df947"
+}
diff --git a/packages/contracts-core/script/configs/devnet/Messaging003AgentRoot.dc.json b/packages/contracts-core/script/configs/devnet/Messaging003AgentRoot.dc.json
new file mode 100644
index 0000000000..0fe837b3aa
--- /dev/null
+++ b/packages/contracts-core/script/configs/devnet/Messaging003AgentRoot.dc.json
@@ -0,0 +1,17 @@
+{
+ "initialAgentRoot": "0x9217e3148f2955ca87ef2b50a553745175a8346a0f46b0ec01f032f3c9aeb8e5",
+ "proofs": {
+ "0x1AebbE69459B80d4975259378577Bc01d2924Cf4": [
+ "0x233c546cc7740219a8b86762a818d32bbd44b31dcf0feb8bb5dd8252b4bcccae",
+ "0x341965897855fc9b044cf7adfaacb1e911e1b556915a9d6466624a54272b547f"
+ ],
+ "0x65c150B7eF3B1adbB9cB2b8041C892b15eDde05A": [
+ "0x58f00a9902fe04863e49cca3696496c64a1e00d71994571fa4e9fb78b6713872",
+ "0x341965897855fc9b044cf7adfaacb1e911e1b556915a9d6466624a54272b547f"
+ ],
+ "0x8230645aC28A4EdD1b0B53E7Cd8019744E9dD559": [
+ "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "0xd3187c6dce38b7b0553221b12b240ed86b9eafc8d9dc9d1be6658c7d3678bc51"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/contracts-core/script/configs/devnet/README.md b/packages/contracts-core/script/configs/devnet/README.md
new file mode 100644
index 0000000000..bbc65c1a5b
--- /dev/null
+++ b/packages/contracts-core/script/configs/devnet/README.md
@@ -0,0 +1,13 @@
+# Configs
+
+[Messaging003AgentRoot.dc.json](Messaging003AgentRoot.dc.json) is automatically generated by the deploy script and contains proofs of the agent root representing the current state of each agent on each chain.
+[Messaging003.dc.json](Messaging003.dc.json) contains the configuration for the Messaging003 contract.
+ agents:
+ - 0: address of the guard(s).
+ - other chains: address of the notary/ies for that chain
+ chainIdSummit: chainId of the Summit chain
+ owner: address of the owner of the contracts. Should match deployer address for devnet.
+
+_Note: Synchain needs no notary_, instead every Notary signature is valid on their remote chain and SynChain at the same time.
+This way they could both submit snapshots to Summit, and attestations to the remote chain.
+
diff --git a/packages/contracts-core/script/utils/DeployerUtils.sol b/packages/contracts-core/script/utils/DeployerUtils.sol
index 3c74d97053..dabf6fe8d0 100644
--- a/packages/contracts-core/script/utils/DeployerUtils.sol
+++ b/packages/contracts-core/script/utils/DeployerUtils.sol
@@ -5,6 +5,7 @@ import {console, Script, stdJson} from "forge-std/Script.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
+import {CREATE3Factory} from "create3/CREATE3Factory.sol";
interface ICreate3Factory {
function deploy(bytes32 salt, bytes memory creationCode) external payable returns (address deployed);
@@ -21,10 +22,14 @@ contract DeployerUtils is Script {
/// @dev Path to artifacts, deployments and configs directories
string private constant ARTIFACTS = "artifacts/";
string private constant DEPLOYMENTS = "deployments/";
- string private constant DEPLOY_CONFIGS = "script/configs/";
+ string private deployConfigs = "script/configs/";
- // TODO: this is only deployed on 7 chains, deploy our own factory for prod deployments
- ICreate3Factory internal constant FACTORY = ICreate3Factory(0x9fBB3DF7C40Da2e5A0dE984fFE2CCB7C47cd0ABf);
+ // @dev wether or not devnet is enabled
+ bool private devnetEnabled = false;
+ // @dev env var for wether or not devnet is in use
+ string private constant DEVNET_ENABLED_VAR = "DEVNET";
+ // @dev artifacted path to use if devnet is enabled;
+ string private constant DEPLOY_CONFIGS_DEVNET = "script/configs/devnet/";
/// @dev Whether the script will be broadcasted or not
bool internal isBroadcasted = false;
@@ -35,6 +40,8 @@ contract DeployerUtils is Script {
uint256 internal broadcasterPK;
address internal broadcasterAddress;
+ ICreate3Factory private factory = ICreate3Factory(0x9fBB3DF7C40Da2e5A0dE984fFE2CCB7C47cd0ABf);
+
bytes32 internal deploymentSalt;
/// @notice Prevents this contract from being included in the coverage report
@@ -54,6 +61,48 @@ contract DeployerUtils is Script {
isBroadcasted = isBroadcasted_;
}
+ // @dev this is called just in time so we can make sure that startBroadcast() is called before this.
+ // it's only overriden and deployed just-in-time in the case of devnet
+ // TODO: this pattern sucks. It introduces potential unexpected behavior if the dev calls factory. directly.
+ // It's also slow.
+ function getFactory() internal returns (ICreate3Factory) {
+ if (!devnetEnabled) {
+ return factory;
+ }
+
+ address factoryDeployment = tryLoadDeployment("CREATE3Factory");
+ if (factoryDeployment == address(0)) {
+ if (broadcasterPK == 0) {
+ console.log("please setup a private key before calling this function");
+ }
+
+ console.log("Create3Factory not deployed on devnet, deploying now");
+ CREATE3Factory NewFactory = new CREATE3Factory();
+ saveDeployment("Create3Factory", "Create3Factory", address(NewFactory), "0x");
+ factoryDeployment = address(NewFactory);
+ }
+ factory = ICreate3Factory(factoryDeployment);
+ return factory;
+ }
+
+ // @dev must be called after setupPK()
+ function setupDevnetIfEnabled() internal {
+ devnetEnabled = vm.envOr(DEVNET_ENABLED_VAR, false);
+
+ if (devnetEnabled) {
+ devnetEnabled = true;
+ // setup the chains
+ setChain("chain_a", Chain("chain_a", 42, "chain_a", "http://localhost:9001/rpc/42"));
+ setChain("chain_b", Chain("chain_b", 43, "chain_b", "http://localhost:9001/rpc/43"));
+ setChain("chain_c", Chain("chain_c", 44, "chain_c", "http://localhost:9001/rpc/44"));
+
+ // override the configs path
+ deployConfigs = DEPLOY_CONFIGS_DEVNET;
+
+ chainAlias = getChainAlias();
+ }
+ }
+
function setupDeployerPK() public {
setupPK("DEPLOYER_PRIVATE_KEY");
}
@@ -83,8 +132,8 @@ contract DeployerUtils is Script {
internal
returns (address deployment)
{
- require(Address.isContract(address(FACTORY)), "Factory not deployed");
- deployment = FACTORY.deploy(
+ require(Address.isContract(address(getFactory())), "Factory not deployed");
+ deployment = getFactory().deploy(
getDeploymentSalt(contractName), // salt
abi.encodePacked(creationCode, constructorArgs) // creation code with appended constructor args
);
@@ -97,9 +146,10 @@ contract DeployerUtils is Script {
}
/// @notice Predicts the deployment address for a contract.
- function predictFactoryDeployment(string memory contractName) internal view returns (address) {
- require(Address.isContract(address(FACTORY)), "Factory not deployed");
- return FACTORY.getDeployed(broadcasterAddress, getDeploymentSalt(contractName));
+ function predictFactoryDeployment(string memory contractName) internal returns (address) {
+ ICreate3Factory _factory = getFactory();
+ require(Address.isContract(address(_factory)), "Factory not deployed");
+ return _factory.getDeployed(broadcasterAddress, getDeploymentSalt(contractName));
}
/// @notice Deploys the contract and saves the deployment artifact
@@ -203,7 +253,7 @@ contract DeployerUtils is Script {
/// @notice Loads deploy config for a given contract on the current chain.
/// Will revert if config doesn't exist.
- function loadDeployConfig(string memory contractName) public view returns (string memory json) {
+ function loadDeployConfig(string memory contractName) public returns (string memory json) {
return vm.readFile(deployConfigPath(contractName));
}
@@ -218,7 +268,7 @@ contract DeployerUtils is Script {
/// @notice Loads deploy config for a given contract on the current chain.
/// Will revert if config doesn't exist.
- function loadGlobalDeployConfig(string memory contractName) public view returns (string memory json) {
+ function loadGlobalDeployConfig(string memory contractName) public returns (string memory json) {
return vm.readFile(globalDeployConfigPath(contractName));
}
@@ -246,14 +296,14 @@ contract DeployerUtils is Script {
}
/// @notice Returns path to the contract deploy config JSON on the current chain.
- function deployConfigPath(string memory contractName) public view returns (string memory path) {
+ function deployConfigPath(string memory contractName) internal returns (string memory path) {
require(bytes(chainAlias).length != 0, "Chain not set");
- return string.concat(DEPLOY_CONFIGS, chainAlias, "/", deployConfigFn(contractName));
+ return string.concat(deployConfigs, chainAlias, "/", deployConfigFn(contractName));
}
/// @notice Returns path to the global contract deploy config JSON.
- function globalDeployConfigPath(string memory contractName) public pure returns (string memory path) {
- return string.concat(DEPLOY_CONFIGS, deployConfigFn(contractName));
+ function globalDeployConfigPath(string memory contractName) public returns (string memory path) {
+ return string.concat(deployConfigs, deployConfigFn(contractName));
}
/// @notice Create directory if it not exists already
diff --git a/services/scribe/cmd/commands.go b/services/scribe/cmd/commands.go
index a5a551f778..cf7853055b 100644
--- a/services/scribe/cmd/commands.go
+++ b/services/scribe/cmd/commands.go
@@ -88,6 +88,7 @@ func createScribeParameters(c *cli.Context) (eventDB db.EventDB, clients map[uin
}
var scribeCommand = &cli.Command{
+ // TODO: rename this command to indexer
Name: "scribe",
Description: "scribe runs the scribe, livefilling across all specified chains",
Flags: []cli.Flag{configFlag, dbFlag, pathFlag},
diff --git a/services/scribe/db/datastore/sql/base/receipt.go b/services/scribe/db/datastore/sql/base/receipt.go
index 3bfdc21f1b..6f86839a1c 100644
--- a/services/scribe/db/datastore/sql/base/receipt.go
+++ b/services/scribe/db/datastore/sql/base/receipt.go
@@ -123,7 +123,7 @@ func (s Store) RetrieveReceiptsWithFilter(ctx context.Context, receiptFilter db.
if err != nil {
return []types.Receipt{}, fmt.Errorf("could not build receipts from db receipts: %w", err)
}
- logger.Infof("[RECEIPT QUERY] Retrieved %d receipts with filter %+v", len(parsedReceipts), receiptFilter)
+
return parsedReceipts, nil
}
@@ -180,7 +180,6 @@ func (s Store) buildReceiptsFromDBReceipts(ctx context.Context, dbReceipts []Rec
page++
logs = append(logs, logGroup...)
}
- logger.Infof("[RECEIPT QUERY] logs collected: %d, %v, page: %d", len(logs), logFilter, page)
parsedReceipt := types.Receipt{
Type: dbReceipt.Type,
@@ -196,11 +195,9 @@ func (s Store) buildReceiptsFromDBReceipts(ctx context.Context, dbReceipts []Rec
BlockNumber: big.NewInt(int64(dbReceipt.BlockNumber)),
TransactionIndex: uint(dbReceipt.TransactionIndex),
}
- logger.Infof("[RECEIPT QUERY] parsedReceipt:, %v", parsedReceipt)
receipts = append(receipts, parsedReceipt)
}
- logger.Infof("[RECEIPT QUERY] parsedReceipt: %d", len(receipts))
return receipts, nil
}