To solve the optimization problem described, we first need to establish a symbolic representation of the variables and the objective function, as well as identify the constraints.

Let's define:
- $x$ as the fraction of each liter that is Egret paint.
- $y$ as the fraction that is Crane paint.

The objective is to minimize the cost. Given that the cost of Egret paint is $0.40 per liter and Crane paint is $1.20 per liter, the total cost for a liter of the mix can be represented by $0.4x + 1.2y$.

Since Bob wants a quality rating of at least 70, and knowing that Egret has a quality rating of 60 and Crane of 85, we can set up the following constraint based on the fractions:
\[60x + 85y \geq 70\]

Additionally, because $x$ and $y$ represent fractions of the paint mix:
- $0 \leq x \leq 1$
- $0 \leq y \leq 1$
- And since we are mixing these two paints to make a liter, $x + y = 1$

Thus, our symbolic representation in JSON format is:
```json
{
    'sym_variables': [('x', 'fraction of Egret paint'), ('y', 'fraction of Crane paint')],
    'objective_function': '0.4*x + 1.2*y',
    'constraints': ['60*x + 85*y >= 70', 'x + y == 1', 'x >= 0', 'x <= 1', 'y >= 0', 'y <= 1']
}
```

Now, let's implement this in Gurobi using Python:

```python
from gurobipy import *

# Create a model
m = Model("Paint_Mix")

# Define variables
x = m.addVar(name='Egret_Paint_Fraction', lb=0, ub=1)
y = m.addVar(name='Crane_Paint_Fraction', lb=0, ub=1)

# Objective function: Minimize cost
m.setObjective(0.4*x + 1.2*y, GRB.MINIMIZE)

# Constraints
m.addConstr(x + y == 1, name='Total_Fraction')
m.addConstr(60*x + 85*y >= 70, name='Quality_Rating')

# Solve the model
m.optimize()

if m.status == GRB.OPTIMAL:
    print("Optimal solution found:")
    print(f"Egret Paint Fraction: {x.x}")
    print(f"Crane Paint Fraction: {y.x}")
    print(f"Total Cost: {m.objVal}")
else:
    print("No optimal solution found")

```