diff --git a/cmd/generate-bindings/generate-bindings.go b/cmd/generate-bindings/generate-bindings.go index fb7b4f8e..7da55c94 100644 --- a/cmd/generate-bindings/generate-bindings.go +++ b/cmd/generate-bindings/generate-bindings.go @@ -200,6 +200,17 @@ func (h *handler) processAbiDirectory(inputs Inputs) error { return fmt.Errorf("no .abi files found in directory: %s", inputs.AbiPath) } + packageNames := make(map[string]bool) + for _, abiFile := range files { + contractName := filepath.Base(abiFile) + contractName = contractName[:len(contractName)-4] + packageName := contractNameToPackage(contractName) + if _, exists := packageNames[packageName]; exists { + return fmt.Errorf("package name collision: multiple contracts would generate the same package name '%s' (contracts are converted to snake_case for package names). Please rename one of your contract files to avoid this conflict", packageName) + } + packageNames[packageName] = true + } + // Process each ABI file for _, abiFile := range files { // Extract contract name from filename (remove .abi extension) diff --git a/cmd/generate-bindings/generate-bindings_test.go b/cmd/generate-bindings/generate-bindings_test.go index c0479aca..e36ed870 100644 --- a/cmd/generate-bindings/generate-bindings_test.go +++ b/cmd/generate-bindings/generate-bindings_test.go @@ -442,6 +442,47 @@ func TestProcessAbiDirectory_NoAbiFiles(t *testing.T) { assert.Contains(t, err.Error(), "no .abi files found") } +func TestProcessAbiDirectory_PackageNameCollision(t *testing.T) { + tempDir, err := os.MkdirTemp("", "generate-bindings-test") + require.NoError(t, err) + defer os.RemoveAll(tempDir) + + abiDir := filepath.Join(tempDir, "abi") + outDir := filepath.Join(tempDir, "generated") + + err = os.MkdirAll(abiDir, 0755) + require.NoError(t, err) + + abiContent := `[{"type":"function","name":"test","inputs":[],"outputs":[]}]` + + // "TestContract" -> "test_contract" + // "test_contract" -> "test_contract" + err = os.WriteFile(filepath.Join(abiDir, "TestContract.abi"), []byte(abiContent), 0600) + require.NoError(t, err) + err = os.WriteFile(filepath.Join(abiDir, "test_contract.abi"), []byte(abiContent), 0600) + require.NoError(t, err) + + logger := zerolog.New(os.Stderr).With().Timestamp().Logger() + runtimeCtx := &runtime.Context{ + Logger: &logger, + } + handler := newHandler(runtimeCtx) + + inputs := Inputs{ + ProjectRoot: tempDir, + ChainFamily: "evm", + Language: "go", + AbiPath: abiDir, + PkgName: "bindings", + OutPath: outDir, + } + + err = handler.processAbiDirectory(inputs) + fmt.Println(err.Error()) + require.Error(t, err) + require.Equal(t, err.Error(), "package name collision: multiple contracts would generate the same package name 'test_contract' (contracts are converted to snake_case for package names). Please rename one of your contract files to avoid this conflict") +} + func TestProcessAbiDirectory_NonExistentDirectory(t *testing.T) { logger := zerolog.New(os.Stderr).With().Timestamp().Logger() runtimeCtx := &runtime.Context{