-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: check interface differences in CI
Adds a new check script to contracts-bedrock that verifies that interfaces being added to the repository accurately represent the interface of the contract that the interface was generated for.
- Loading branch information
1 parent
7373ce7
commit a898242
Showing
3 changed files
with
121 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
packages/contracts-bedrock/scripts/checks/check-interfaces.sh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
#!/usr/bin/env bash | ||
set -euo pipefail | ||
|
||
# This script checks for ABI consistency between interfaces and their corresponding contracts. | ||
# It compares the ABIs of interfaces (files starting with 'I') with their implementation contracts, | ||
# excluding constructors and certain predefined files. The script reports any differences found | ||
# and exits with an error if inconsistencies are detected. | ||
|
||
# Grab the directory of the contracts-bedrock package | ||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) | ||
CONTRACTS_BASE=$(dirname "$(dirname "$SCRIPT_DIR")") | ||
|
||
# Define the files to exclude (patterns can be used) | ||
EXCLUDE_FILES=( | ||
# External dependencies | ||
"IMulticall3" | ||
"IERC20" | ||
"IERC721" | ||
"IERC721Enumerable" | ||
"IERC721Metadata" | ||
"IERC721Upgradeable" | ||
"IERC721Receiver" | ||
"IERC1271" | ||
"IERC165" | ||
"IVotes" | ||
"IBeacon" | ||
"IProxyCreationCallback" | ||
"IAutomate" | ||
"IGelato1Balance" | ||
|
||
# EAS | ||
"IEAS" | ||
"ISchemaResolver" | ||
"ISchemaRegistry" | ||
|
||
# TODO: Interfaces that need to be fixed | ||
"IDisputeGameFactory" | ||
"IPreimageOracle" | ||
"IOptimismMintableERC721" | ||
"IFaultDisputeGame" | ||
"IInitializable" | ||
"IAddressManager" | ||
"IDelayedWETH" | ||
"IWETH" | ||
"IAnchorStateRegistry" | ||
"ICrossL2Inbox" | ||
"IL2ToL2CrossDomainMessenger" | ||
) | ||
|
||
# Find all JSON files in the forge-artifacts folder | ||
JSON_FILES=$(find "$CONTRACTS_BASE/forge-artifacts" -type f -name "*.json") | ||
|
||
# Initialize a flag to track if any differences are detected | ||
differences_detected=false | ||
|
||
# Iterate over all JSON files | ||
for interface_file in $JSON_FILES; do | ||
# Extract contract kind and name | ||
contract_kind=$(jq -r '.ast.nodes[] | select(.nodeType == "ContractDefinition") | .contractKind' < "$interface_file") | ||
contract_name=$(jq -r '.ast.nodes[] | select(.nodeType == "ContractDefinition") | .name' < "$interface_file") | ||
|
||
# Skip excluded files | ||
skip=false | ||
for exclude in "${EXCLUDE_FILES[@]}"; do | ||
if [[ "$interface_file" == *"$exclude"* ]]; then | ||
skip=true | ||
break | ||
fi | ||
done | ||
|
||
# Continue to the next file if it should be skipped | ||
if [ "$skip" = true ]; then | ||
continue | ||
fi | ||
|
||
# If contract kind is "interface" and name starts with "I" | ||
if [[ "$contract_kind" == "interface" && "$contract_name" == I* ]]; then | ||
# Construct the corresponding contract name by removing the leading "I" | ||
contract_basename=${contract_name:1} | ||
corresponding_contract_file="$CONTRACTS_BASE/forge-artifacts/$contract_basename.sol/$contract_basename.json" | ||
|
||
# Check if the corresponding contract file exists | ||
if [ -f "$corresponding_contract_file" ]; then | ||
# Extract and compare ABIs excluding constructors | ||
interface_abi=$(jq '[.abi[] | select(.type != "constructor")]' < "$interface_file") | ||
contract_abi=$(jq '[.abi[] | select(.type != "constructor")]' < "$corresponding_contract_file") | ||
|
||
# Use jq to compare the ABIs | ||
diff_result=$(diff -u <(echo "$interface_abi" | jq -S .) <(echo "$contract_abi" | jq -S .)) | ||
|
||
if [ -n "$diff_result" ]; then | ||
echo "Differences found in ABI between $contract_name and $contract_basename:" | ||
echo "$diff_result" | ||
differences_detected=true | ||
fi | ||
fi | ||
fi | ||
done | ||
|
||
# Fail the script if any differences were detected | ||
if [ "$differences_detected" = true ]; then | ||
echo "Differences detected in ABI comparisons. Please review the differences above." | ||
echo "If the interface is an external dependency or should otherwise be excluded from this" | ||
echo "check, add the interface name to the EXCLUDE_FILES list in the script. This will prevent" | ||
echo "the script from comparing it against a corresponding contract." | ||
exit 1 | ||
else | ||
exit 0 | ||
fi |