Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
484 lines (403 loc) Β· 16.6 KB
/
Copy pathMakefile
File metadata and controls
484 lines (403 loc) Β· 16.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
# Forge is not safe to run concurrently: parallel invocations race on the
# compilation cache and on the solc downloads performed by svm-rs.
.NOTPARALLEL:
.PHONY: build
.PHONY: build-all
.PHONY: check-foundry-version
.PHONY: clean
.PHONY: codegen
.PHONY: coverage
.PHONY: deploy-livenets
.PHONY: deploy-mainnets
.PHONY: deploy-testnets
.PHONY: devnet
.PHONY: install-deps
.PHONY: install-foundry
.PHONY: print-foundry-version
.PHONY: publish-soldeer-package
.PHONY: release-artifacts
.PHONY: rust-bindings
.PHONY: test
.PHONY: verify-livenets
.PHONY: verify-mainnets
.PHONY: verify-testnets
# ------------------------------------------------------------------------------
# Auxiliary definitions
# ------------------------------------------------------------------------------
NOOP =
SPACE = $(NOOP) $(NOOP)
TO_UPPER = $(subst a,A,$(subst b,B,$(subst c,C,$(subst d,D,$(subst e,E,\
$(subst f,F,$(subst g,G,$(subst h,H,$(subst i,I,$(subst j,J,\
$(subst k,K,$(subst l,L,$(subst m,M,$(subst n,N,$(subst o,O,\
$(subst p,P,$(subst q,Q,$(subst r,R,$(subst s,S,$(subst t,T,\
$(subst u,U,$(subst v,V,$(subst w,W,$(subst x,X,$(subst y,Y,\
$(subst z,Z,$(1)))))))))))))))))))))))))))
KEBAB_TO_SCREAMING_SNAKE = $(call TO_UPPER,$(subst -,_,$(1)))
# ------------------------------------------------------------------------------
# Project metadata
# ------------------------------------------------------------------------------
PROJECT_NAME := cartesi-rollups-contracts
MAJOR_VERSION := 3
MINOR_VERSION := 0
PATCH_VERSION := 0
PRE_RELEASE := alpha.10
BUILD_METADATA :=
VERSION := $(MAJOR_VERSION).$(MINOR_VERSION).$(PATCH_VERSION)
VERSION := $(VERSION)$(if $(PRE_RELEASE),-$(PRE_RELEASE))
VERSION := $(VERSION)$(if $(BUILD_METADATA),+$(BUILD_METADATA))
# ------------------------------------------------------------------------------
# Dependency versions
# ------------------------------------------------------------------------------
FOUNDRY_VERSION := 1.5.1
# ------------------------------------------------------------------------------
# Release artifacts (bundles)
# ------------------------------------------------------------------------------
BUNDLE_PREFIX := dist/$(PROJECT_NAME)-$(VERSION)
ARTIFACTS_BUNDLE := $(BUNDLE_PREFIX)-artifacts.tar.gz
DEPLOYMENT_ADDRESSES_BUNDLE := $(BUNDLE_PREFIX)-deployment-addresses.tar.gz
DEVNET_BUNDLE := $(BUNDLE_PREFIX)-anvil-$(FOUNDRY_VERSION).tar.gz
RELEASE_ARTIFACTS += $(ARTIFACTS_BUNDLE)
RELEASE_ARTIFACTS += $(DEPLOYMENT_ADDRESSES_BUNDLE)
RELEASE_ARTIFACTS += $(DEVNET_BUNDLE)
# ------------------------------------------------------------------------------
# Dependencies
# ------------------------------------------------------------------------------
ANVIL := anvil
CAST := cast
FORGE := forge
FOUNDRYUP := foundryup
GENHTML := genhtml
GIT := git
# ------------------------------------------------------------------------------
# Commands
# ------------------------------------------------------------------------------
CODEGEN_CMD = $(FORGE) script script/CodeGeneration.s.sol:$(1)
DEPLOY_CMD := $(FORGE) script script/Deployment.s.sol:DeploymentScript
VERIFY_CMD := $(FORGE) verify-contract --guess-constructor-args --watch
# ------------------------------------------------------------------------------
# Anvil devnet
# ------------------------------------------------------------------------------
ANVIL_CHAIN_ID := 31337
ANVIL_PK0 := 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
ANVIL_RPC_URL := http://127.0.0.1:8545
ANVIL_STATE := state.json
ANVIL_RUNTIME_OPTS += --dump-state $(ANVIL_STATE)
ANVIL_RUNTIME_OPTS += --preserve-historical-states
ANVIL_RUNTIME_OPTS += --quiet
ANVIL_DEPLOY_OPTS += --private-key $(ANVIL_PK0)
ANVIL_DEPLOY_OPTS += --rpc-url $(ANVIL_RPC_URL)
ANVIL_DEPLOY_OPTS += --non-interactive
ANVIL_DEPLOY_OPTS += --broadcast
ANVIL_DEPLOY_OPTS += --slow
# ------------------------------------------------------------------------------
# Supported (live) networks
# ------------------------------------------------------------------------------
CHAIN_ID.arb-mainnet := 42161
CHAIN_ID.arb-sepolia := 421614
CHAIN_ID.base-mainnet := 8453
CHAIN_ID.base-sepolia := 84532
CHAIN_ID.eth-mainnet := 1
CHAIN_ID.eth-sepolia := 11155111
CHAIN_ID.opt-mainnet := 10
CHAIN_ID.opt-sepolia := 11155420
LABEL.arb-mainnet := Arbitrum Mainnet
LABEL.arb-sepolia := Arbitrum Sepolia
LABEL.base-mainnet := Base Mainnet
LABEL.base-sepolia := Base Sepolia
LABEL.eth-mainnet := Ethereum Mainnet
LABEL.eth-sepolia := Ethereum Sepolia
LABEL.opt-mainnet := OP Mainnet
LABEL.opt-sepolia := OP Sepolia
TESTNETS := arb-sepolia base-sepolia eth-sepolia opt-sepolia
MAINNETS := arb-mainnet base-mainnet eth-mainnet opt-mainnet
LIVENETS := $(TESTNETS) $(MAINNETS)
# The RPC URL alias is the chain name with underscores, as in foundry.toml
# $(1) = chain name, e.g. eth-mainnet
define CHAIN_OPTS_TEMPLATE
CHAIN_OPTS.$(1) := --rpc-url $(subst -,_,$(1)) --chain-id $(CHAIN_ID.$(1))
endef
# Define a CHAIN_OPTS.<chain> variable for each livenet
$(foreach n,$(LIVENETS),$(eval $(call CHAIN_OPTS_TEMPLATE,$(n))))
ifdef ALCHEMY_API_KEY
ALCHEMY_RPC_URL = https://$(1).g.alchemy.com/v2/$(ALCHEMY_API_KEY)
$(foreach n,$(LIVENETS),$(eval RPC_URL.$(n) := $(call ALCHEMY_RPC_URL,$(n))))
else
RPC_URL.arb-mainnet := https://arb1.arbitrum.io/rpc
RPC_URL.arb-sepolia := https://sepolia-rollup.arbitrum.io/rpc
RPC_URL.base-mainnet := https://mainnet.base.org
RPC_URL.base-sepolia := https://sepolia.base.org
RPC_URL.eth-mainnet := https://eth.drpc.org
RPC_URL.eth-sepolia := https://sepolia.drpc.org
RPC_URL.opt-mainnet := https://mainnet.optimism.io
RPC_URL.opt-sepolia := https://sepolia.optimism.io
endif
# The RPC URL environment variable name is the chain name converted to
# screaming snake case and suffixed with _RPC_URL as in foundry.toml
# $(1) = chain name, e.g. eth-mainnet
define RPC_URL_ENV_TEMPLATE
$(call KEBAB_TO_SCREAMING_SNAKE,$(1))_RPC_URL ?= $$(RPC_URL.$(1))
export $(call KEBAB_TO_SCREAMING_SNAKE,$(1))_RPC_URL
endef
# Define and export a <CHAIN>_RPC_URL variable for each livenet
$(foreach n,$(LIVENETS),$(eval $(call RPC_URL_ENV_TEMPLATE,$(n))))
TESTNET_CHAIN_IDS := $(foreach n,$(TESTNETS),$(CHAIN_ID.$(n)))
MAINNET_CHAIN_IDS := $(foreach n,$(MAINNETS),$(CHAIN_ID.$(n)))
LIVENET_CHAIN_IDS := $(TESTNET_CHAIN_IDS) $(MAINNET_CHAIN_IDS)
# ------------------------------------------------------------------------------
# Contracts
# ------------------------------------------------------------------------------
DEPLOYED_CORE_CONTRACTS += ApplicationFactory
DEPLOYED_CORE_CONTRACTS += AuthorityFactory
DEPLOYED_CORE_CONTRACTS += Erc1155BatchPortal
DEPLOYED_CORE_CONTRACTS += Erc1155SinglePortal
DEPLOYED_CORE_CONTRACTS += Erc20Portal
DEPLOYED_CORE_CONTRACTS += Erc721Portal
DEPLOYED_CORE_CONTRACTS += EtherPortal
DEPLOYED_CORE_CONTRACTS += InputBox
DEPLOYED_CORE_CONTRACTS += QuorumFactory
DEPLOYED_CORE_CONTRACTS += RefundOutputBuilder
DEPLOYED_CORE_CONTRACTS += SafeErc20Transfer
DEPLOYED_CORE_CONTRACTS += SelfHostedApplicationFactory
DEPLOYED_CORE_CONTRACTS += UsdWithdrawalOutputBuilderFactory
PUBLIC_CONTRACTS += $(DEPLOYED_CORE_CONTRACTS)
PUBLIC_CONTRACTS += IApplication
PUBLIC_CONTRACTS += IApplicationFactory
PUBLIC_CONTRACTS += IAuthority
PUBLIC_CONTRACTS += IAuthorityFactory
PUBLIC_CONTRACTS += IConsensus
PUBLIC_CONTRACTS += IERC1155
PUBLIC_CONTRACTS += IERC1155MetadataURI
PUBLIC_CONTRACTS += IERC1155Receiver
PUBLIC_CONTRACTS += IERC165
PUBLIC_CONTRACTS += IERC20
PUBLIC_CONTRACTS += IERC20Metadata
PUBLIC_CONTRACTS += IERC721
PUBLIC_CONTRACTS += IERC721Metadata
PUBLIC_CONTRACTS += IERC721Receiver
PUBLIC_CONTRACTS += IErc1155BatchPortal
PUBLIC_CONTRACTS += IErc1155SinglePortal
PUBLIC_CONTRACTS += IErc20Portal
PUBLIC_CONTRACTS += IErc721Portal
PUBLIC_CONTRACTS += IEtherPortal
PUBLIC_CONTRACTS += IInputBox
PUBLIC_CONTRACTS += IOutputsMerkleRootValidator
PUBLIC_CONTRACTS += IQuorum
PUBLIC_CONTRACTS += IQuorumFactory
PUBLIC_CONTRACTS += IRefundOutputBuilder
PUBLIC_CONTRACTS += ISafeErc20Transfer
PUBLIC_CONTRACTS += ISelfHostedApplicationFactory
PUBLIC_CONTRACTS += IUsdWithdrawalOutputBuilder
PUBLIC_CONTRACTS += IUsdWithdrawalOutputBuilderFactory
PUBLIC_CONTRACTS += IWithdrawalOutputBuilder
PUBLIC_CONTRACTS += Inputs
PUBLIC_CONTRACTS += Outputs
PUBLIC_CONTRACTS += TestFungibleToken
PUBLIC_CONTRACTS += TestMultiToken
PUBLIC_CONTRACTS += TestNonFungibleToken
PUBLIC_CONTRACTS += TestUsdc
PUBLIC_CONTRACTS += draft-IERC6093
# ------------------------------------------------------------------------------
# Solidity dependencies
# ------------------------------------------------------------------------------
DEPENDENCIES := dependencies
DEPENDENCIES_STAMP := $(DEPENDENCIES)/.installed
# ------------------------------------------------------------------------------
# Rust bindings generation options
# ------------------------------------------------------------------------------
CRATE_DESCRIPTION := Rust bindings for Cartesi Rollups contracts
FORGE_BIND_OPTS += --skip test
FORGE_BIND_OPTS += --select "^($(subst $(SPACE),|,$(PUBLIC_CONTRACTS)))$$"
FORGE_BIND_OPTS += --crate-name "$(PROJECT_NAME)"
FORGE_BIND_OPTS += --crate-version "$(VERSION)"
FORGE_BIND_OPTS += --crate-license "Apache-2.0"
FORGE_BIND_OPTS += --crate-description "$(CRATE_DESCRIPTION)"
FORGE_BIND_OPTS += --alloy-version 2
# ------------------------------------------------------------------------------
# Generated files
# ------------------------------------------------------------------------------
GENERATED_FILE_DEPLOYERS := script/utils/ContractDeployers.sol
GENERATED_FILE_VERSION := src/common/Version.sol
GENERATED_FILES += $(GENERATED_FILE_DEPLOYERS)
GENERATED_FILES += $(GENERATED_FILE_VERSION)
# ------------------------------------------------------------------------------
# Tar deterministic archive-creation options
# ------------------------------------------------------------------------------
TAR_DETERMINISTIC_CREATE_OPTS += --sort=name
TAR_DETERMINISTIC_CREATE_OPTS += --mtime=@0
TAR_DETERMINISTIC_CREATE_OPTS += --owner=1000
TAR_DETERMINISTIC_CREATE_OPTS += --group=1000
TAR_DETERMINISTIC_CREATE_OPTS += --numeric-owner
TAR_DETERMINISTIC_CREATE_OPTS += --mode=a=rX,u+w
# ------------------------------------------------------------------------------
# Deployment artifacts
# ------------------------------------------------------------------------------
DEPLOYMENTS := deployments
DEVNET_DEPLOYMENTS_DIR := $(DEPLOYMENTS)/$(ANVIL_CHAIN_ID)
LIVENET_DEPLOYMENTS_DIRS := $(addprefix $(DEPLOYMENTS)/, $(LIVENET_CHAIN_IDS))
# ------------------------------------------------------------------------------
# Rules
# ------------------------------------------------------------------------------
build: $(DEPENDENCIES_STAMP)
@$(FORGE) build --skip test
build-all: $(DEPENDENCIES_STAMP)
@$(FORGE) build
# -X honors personal (local or global) ignore rules
# -d removes directories recursively
# -ff removes git-sourced Soldeer dependencies
clean:
@$(GIT) clean -Xdff
codegen: $(GENERATED_FILES)
$(GENERATED_FILE_DEPLOYERS): CODEGEN_SCRIPT := DeployersCodeGenerationScript
$(GENERATED_FILE_VERSION): CODEGEN_SCRIPT := VersionCodeGenerationScript
$(GENERATED_FILE_VERSION): CODEGEN_ARGS += "$(MAJOR_VERSION)"
$(GENERATED_FILE_VERSION): CODEGEN_ARGS += "$(MINOR_VERSION)"
$(GENERATED_FILE_VERSION): CODEGEN_ARGS += "$(PATCH_VERSION)"
$(GENERATED_FILE_VERSION): CODEGEN_ARGS += "$(PRE_RELEASE)"
$(GENERATED_FILE_VERSION): CODEGEN_ARGS += "$(BUILD_METADATA)"
.PHONY: $(GENERATED_FILES)
$(GENERATED_FILES): $(DEPENDENCIES_STAMP)
@echo "π§ Generating $@..."
@$(call CODEGEN_CMD,$(CODEGEN_SCRIPT)) -- $(CODEGEN_ARGS)
@$(FORGE) fmt $@
@echo "β
Generated $@."
coverage: $(DEPENDENCIES_STAMP)
@echo "π§ Generating coverage data..."
@$(FORGE) coverage --ir-minimum --report lcov --lcov-version 2.0
@echo "π§ Generating coverage report..."
@$(GENHTML) -o coverage lcov.info --rc derive_function_end_line=0
@echo "β
Successfully generated coverage report."
devnet: check-foundry-version $(DEPENDENCIES_STAMP)
@set -eu; \
echo "π¨ Building Anvil devnet..." ; \
cleanup() { \
exit_code=$$?; \
if kill -0 "$${anvil_pid}" 2>/dev/null; then \
echo "π§ Killing Anvil (PID $${anvil_pid})..."; \
kill "$${anvil_pid}"; \
echo "π§ Waiting for Anvil to finish...."; \
wait "$${anvil_pid}"; \
errno=$$?; \
if [ "$${errno}" -eq 0 ]; then \
echo "β
Anvil exited with code $${errno}"; \
else \
echo "β Anvil exited with code $${errno}"; \
if [ "$${exit_code}" -eq 0 ]; then \
exit_code=$${errno}; \
fi; \
fi; \
else \
echo "π‘ Anvil (PID $${anvil_pid}) exited early"; \
fi; \
exit "$${exit_code}"; \
}; \
trap cleanup EXIT; \
echo "π§ Spawning Anvil..."; \
$(ANVIL) $(ANVIL_RUNTIME_OPTS) & \
anvil_pid=$$!; \
echo "β
Anvil spawned!"; \
listening=0; \
i=0; \
while [ "$$i" -lt 5 ]; do \
echo "π§ Pinging Anvil..."; \
if $(CAST) chain-id >/dev/null 2>/dev/null; then \
echo "β
Anvil is listening!"; \
listening=1; \
break; \
else \
echo "π§ Anvil is not listening yet. Waiting 1s..."; \
sleep 1; \
fi; \
i=$$((i+1)); \
done; \
if [ "$${listening}" -eq 0 ]; then \
echo "β Anvil did not respond within 5s." >&2; \
exit 1; \
fi; \
echo "π¨ Deploying to Anvil (Chain ID: $(ANVIL_CHAIN_ID))..."; \
$(DEPLOY_CMD) $(ANVIL_DEPLOY_OPTS) ; \
echo "β
Successfully built Anvil devnet."
deploy-livenets: deploy-testnets deploy-mainnets
deploy-testnets: $(addprefix deploy-,$(TESTNETS))
deploy-mainnets: $(addprefix deploy-,$(MAINNETS))
# $(1) = chain name, e.g. eth-mainnet
define DEPLOY_CHAIN_RULE_TEMPLATE
.PHONY: deploy-$(1)
deploy-$(1): $$(DEPENDENCIES_STAMP)
@echo "π Running deployment script against $(LABEL.$(1))..."
@$$(DEPLOY_CMD) $$(CHAIN_OPTS.$(1)) $$(DEPLOY_OPTS)
@echo "β
Deployment script successfully ran against $(LABEL.$(1))."
endef
# Define a deploy-<chain> rule for each livenet
$(foreach n,$(LIVENETS),$(eval $(call DEPLOY_CHAIN_RULE_TEMPLATE,$(n))))
check-foundry-version:
@set -eu; \
for tool in $(FORGE) $(CAST) $(ANVIL); do \
if ! command -v "$${tool}" >/dev/null 2>&1; then \
echo "β $${tool} not found in PATH." >&2; \
exit 1; \
fi; \
installed=$$($${tool} --version 2>/dev/null | sed -nE \
's/[^0-9]*([0-9]+\.[0-9]+\.[0-9]+).*/\1/p'); \
if [ -z "$${installed}" ]; then \
echo "β Could not parse $${tool} version." >&2; \
exit 1; \
fi; \
if [ "$${installed}" != "$(FOUNDRY_VERSION)" ]; then \
printf 'β Found %s %s, expected %s.\n' $${tool} \
"$${installed}" $(FOUNDRY_VERSION) >&2; \
exit 1; \
fi; \
done; \
echo "β
Foundry $(FOUNDRY_VERSION) confirmed (forge, cast, anvil)."
install-deps: $(DEPENDENCIES_STAMP)
$(DEPENDENCIES_STAMP): foundry.toml soldeer.lock
@$(FORGE) soldeer install
@mkdir -p $(@D)
@touch $@
install-foundry:
@$(FOUNDRYUP) -i "$(FOUNDRY_VERSION)"
print-foundry-version:
@echo "$(FOUNDRY_VERSION)"
publish-soldeer-package:
@$(FORGE) soldeer push "$(PROJECT_NAME)~$(VERSION)" \
$(if $(filter-out 0 n no false,$(DRY_RUN)),--dry-run)
release-artifacts: $(RELEASE_ARTIFACTS)
$(ARTIFACTS_BUNDLE): build
$(ARTIFACTS_BUNDLE): TAR_ARGS += -C out
$(ARTIFACTS_BUNDLE): TAR_ARGS += $(addsuffix .sol, $(PUBLIC_CONTRACTS))
$(DEPLOYMENT_ADDRESSES_BUNDLE): deploy-livenets
$(DEPLOYMENT_ADDRESSES_BUNDLE): TAR_ARGS += $(LIVENET_DEPLOYMENTS_DIRS)
$(DEVNET_BUNDLE): devnet
$(DEVNET_BUNDLE): TAR_ARGS += $(DEVNET_DEPLOYMENTS_DIR)
$(DEVNET_BUNDLE): TAR_ARGS += $(ANVIL_STATE)
$(RELEASE_ARTIFACTS):
@echo "π¦ Creating $@..."
@mkdir -p $(@D)
@tar $(TAR_DETERMINISTIC_CREATE_OPTS) -czf $@ $(TAR_ARGS)
@echo "β
Created $@."
rust-bindings: $(DEPENDENCIES_STAMP)
@$(FORGE) bind $(FORGE_BIND_OPTS)
test: $(DEPENDENCIES_STAMP)
@$(FORGE) test -vvv
verify-livenets: verify-testnets verify-mainnets
verify-testnets: $(addprefix verify-,$(TESTNETS))
verify-mainnets: $(addprefix verify-,$(MAINNETS))
# $(1) = chain name, e.g. eth-mainnet
# $(2) = contract name, e.g. InputBox
define VERIFY_CONTRACT_RULE_TEMPLATE
.PHONY: verify-$(1)-$(2)
verify-$(1)-$(2): $(DEPLOYMENTS)/$(CHAIN_ID.$(1))/$(2).txt
@echo "π Verifying $(2) on $(LABEL.$(1))..."
@$$(VERIFY_CMD) $$(CHAIN_OPTS.$(1)) $$(VERIFY_OPTS) -- \
"$$$$(cat $$<)" "$(2)"
endef
# $(1) = chain name, e.g. eth-mainnet
define VERIFY_CHAIN_RULE_TEMPLATE
.PHONY: verify-$(1)
verify-$(1): $$(addprefix verify-$(1)-,$$(DEPLOYED_CORE_CONTRACTS))
@echo "β
Verified deployments on $(LABEL.$(1))."
$$(foreach c,$$(DEPLOYED_CORE_CONTRACTS),\
$$(eval $$(call VERIFY_CONTRACT_RULE_TEMPLATE,$(1),$$(c))))
endef
# Define verify-<chain> and verify-<chain>-<contract> rules for each livenet
$(foreach n,$(LIVENETS),$(eval $(call VERIFY_CHAIN_RULE_TEMPLATE,$(n))))