diff --git a/src/analysis/fba.jl b/src/analysis/fba.jl
index 2e15bf838e2017034e8883ab35aa34d1df4d427a..f5adcfdd363e57eeed2b5bfa0964bb7f9939f4e7 100644
--- a/src/analysis/fba.jl
+++ b/src/analysis/fba.jl
@@ -21,7 +21,8 @@ of the model, if the solution is found.
 Arguments are passed to [`flux_balance_analysis`](@ref).
 """
 function flux_balance_analysis_vec(args...)::Union{Vector{Float64},Nothing}
-    (optmodel, vars) = flux_balance_analysis(args...)
+    optmodel = flux_balance_analysis(args...)
+    vars = optmodel[:x]
 
     termination_status(optmodel) in [MOI.OPTIMAL, MOI.LOCALLY_SOLVED] || return nothing
     value.(vars)
@@ -71,7 +72,8 @@ function fba(
     sense = MOI.MAX_SENSE,
 )
     # get core optimization problem
-    cbm, v, mb, lbcons, ubcons = make_optimization_model(model, optimizer, sense = sense)
+    cbm = make_optimization_model(model, optimizer, sense = sense)
+    v = cbm[:x] # fluxes
 
     # modify core optimization problem according to user specifications
     if !isempty(solver_attributes) # set other attributes
@@ -83,7 +85,7 @@ function fba(
     # set additional constraints
     for (rxnid, con) in constraints
         ind = model.reactions[findfirst(model.reactions, rxnid)]
-        set_bound(ind, lbcons, ubcons; lb = con[1], ub = con[2])
+        set_bound(ind, cbm; lb = con[1], ub = con[2])
     end
 
     # if an objective function is supplied, modify the default objective
diff --git a/src/analysis/fva.jl b/src/analysis/fva.jl
index 0b38dc87179e3d82db28c96b2f5abcd4db8a0f6c..e1c5a575c1470b3341423f9d3095d1cd532efda9 100644
--- a/src/analysis/fva.jl
+++ b/src/analysis/fva.jl
@@ -37,14 +37,15 @@ function flux_variability_analysis(
         throw(DomainError(reactions, "Index exceeds number of reactions."))
     end
 
-    (optimization_model, x0) = flux_balance_analysis(model, optimizer)
+    optimization_model = flux_balance_analysis(model, optimizer)
     Z0 = COBREXA.JuMP.objective_value(optimization_model)
     optimization_model = nothing # we won't need this one anymore, so free the memory
 
     # store a JuMP optimization model at all workers
     save_model = :(
         begin
-            optmodel, x = COBREXA.make_optimization_model($model, $optimizer)
+            optmodel = COBREXA.make_optimization_model($model, $optimizer)
+            x = optmodel[:x]
             COBREXA._FVA_add_constraint(optmodel, $(objective(model)), x, $Z0, $gamma)
             optmodel
         end
@@ -140,7 +141,8 @@ function fva(
     constraints = Dict{String,Tuple{Float64,Float64}}(),
     sense = MOI.MAX_SENSE,
 )
-    cbm, v, mb, lbcons, ubcons = make_optimization_model(model, optimizer, sense = sense)
+    cbm = make_optimization_model(model, optimizer, sense = sense)
+    v = cbm[:x]
 
     if !isempty(solver_attributes) # set other attributes
         for (k, v) in solver_attributes
@@ -151,7 +153,7 @@ function fva(
     # set additional constraints
     for (rxnid, con) in constraints
         ind = model.reactions[findfirst(model.reactions, rxnid)]
-        set_bound(ind, lbcons, ubcons; lb = con[1], ub = con[2])
+        set_bound(ind, cbm; lb = con[1], ub = con[2])
     end
 
     # if an objective function is supplied, modify the default objective
diff --git a/src/analysis/pfba.jl b/src/analysis/pfba.jl
index 1e2afc4139a4494610cda97493d8da0643a5a941..8402d3f4da2052a72ddc9f9003a211a1d44c4047 100644
--- a/src/analysis/pfba.jl
+++ b/src/analysis/pfba.jl
@@ -33,16 +33,16 @@ function pfba(
 
 
     if typeof(optimizer) <: AbstractArray # choose optimizer
-        cbm, v, mb, lbcons, ubcons =
-            make_optimization_model(model, optimizer[1], sense = sense)
+        cbm = make_optimization_model(model, optimizer[1], sense = sense)
+        v = cbm[:x]
         if !isempty(solver_attributes["opt1"]) # set other attributes
             for (k, v) in solver_attributes["opt1"]
                 set_optimizer_attribute(cbm, k, v)
             end
         end
     else # singe optimizer
-        cbm, v, mb, lbcons, ubcons =
-            make_optimization_model(model, optimizer, sense = sense)
+        cbm = make_optimization_model(model, optimizer, sense = sense)
+        v = cbm[:x]
         if !isempty(solver_attributes) # set other attributes
             for (k, v) in solver_attributes
                 set_optimizer_attribute(cbm, k, v)
@@ -53,7 +53,7 @@ function pfba(
     # set additional constraints
     for (rxnid, con) in constraints
         ind = model.reactions[findfirst(model.reactions, rxnid)]
-        set_bound(ind, lbcons, ubcons; lb = con[1], ub = con[2])
+        set_bound(ind, cbm; lb = con[1], ub = con[2])
     end
 
     # check if default objective should be used
diff --git a/src/base/solver.jl b/src/base/solver.jl
index 178654463f73c57a05844438ca73c0cdf8674620..b8d16887170516b01d66a9bc8d4e31c08e5f8a66 100644
--- a/src/base/solver.jl
+++ b/src/base/solver.jl
@@ -13,11 +13,11 @@ function make_optimization_model(
     optimization_model = COBREXA.JuMP.Model(optimizer)
     @variable(optimization_model, x[i = 1:n])
     @objective(optimization_model, sense, objective(model)' * x)
-    mb = @constraint(optimization_model, mb, stoichiometry(model) * x .== balance(model)) # mass balance
-    lbs = @constraint(optimization_model, lbs, xl .<= x) # lower bounds
-    ubs = @constraint(optimization_model, ubs, x .<= xu) # upper bounds
+    @constraint(optimization_model, mb, stoichiometry(model) * x .== balance(model)) # mass balance
+    @constraint(optimization_model, lbs, xl .<= x) # lower bounds
+    @constraint(optimization_model, ubs, x .<= xu) # upper bounds
 
-    return optimization_model, x, mb, lbs, ubs
+    return optimization_model
 end
 
 """
@@ -28,8 +28,7 @@ function optimize_model(
     optimizer;
     sense = MOI.MIN_SENSE,
 ) where {LM<:MetabolicModel}
-    optimization_model, x, _, _, _ =
-        make_optimization_model(model, optimizer; sense = sense)
-        COBREXA.JuMP.optimize!(optimization_model)
-    return (optimization_model, x)
+    optimization_model = make_optimization_model(model, optimizer; sense = sense)
+    COBREXA.JuMP.optimize!(optimization_model)
+    return optimization_model
 end
diff --git a/src/base/utilities.jl b/src/base/utilities.jl
index 6ea40a1767aae5e13e9b23f6a48d0c07c804d242..ac473dd5677cb0e740583539a7939ae4fabd251d 100644
--- a/src/base/utilities.jl
+++ b/src/base/utilities.jl
@@ -21,16 +21,16 @@ Base.copy(model::CoupledLinearModel) =
 
 
 """
-    set_bound(index, ubconstaintref, lbconstaintref; ub=1000, lb=-1000)
+    set_bound(index, optimization_model; ub=1000, lb=-1000)
 Helper function to set the bounds of variables.
 The JuMP `set_normalized_rhs` function is a little confusing, so this function simplifies setting
-constraints. Just supply the constraint `index` and the bound objects (`ubconstaintref`, `lbconstaintref`) and they will be set to `ub` and `lb`.
+constraints. Just supply the constraint `index` and the model and they will be set to `ub` and `lb`.
 """
-function set_bound(vind, lbs, ubs; ub = 1000, lb = -1000)
+function set_bound(vind, opt_model; ub = 1000, lb = -1000)
     if lb <= 0
-        set_normalized_rhs(lbs[vind], abs(lb))
+        set_normalized_rhs(opt_model[:lbs][vind], abs(lb))
     else
-        set_normalized_rhs(lbs[vind], -abs(lb))
+        set_normalized_rhs(opt_model[:lbs][vind], -abs(lb))
     end
-    set_normalized_rhs(ubs[vind], ub)
+    set_normalized_rhs(opt_model[:ubs][vind], ub)
 end
diff --git a/src/sampling/sampling_tools.jl b/src/sampling/sampling_tools.jl
index 0762c4cf5af0d6560963b69cd7542417fbe6c202..083c53dcd967389113a44e3cca42ae9c04a26371 100644
--- a/src/sampling/sampling_tools.jl
+++ b/src/sampling/sampling_tools.jl
@@ -1,14 +1,17 @@
 """
-    get_warmup_points(cbmodel, v, mb, lbs, ubs; random_objective=false, numstop=1e10)
+    get_warmup_points(cbm; random_objective=false, numstop=1e10)
 
-Generate warmup points for all the reactions on the model that
+Generate warmup points for all the reactions in the model that
 are not fixed. Assumes you feed in a JuMP model that is already
-constrained i.e. the constrains are already applied into cbmodel.
-Note, extra constraints applied to ubs and lbs will have no effect.
+constrained i.e. the constrains are already applied into `cbm`.
 
-numstop = 2*number of warmup points - to reduce the time this takes
+numstop (maximum value is 2*number of warmup points). Reduce this to prematurely 
+stop finding warmup points.
 """
-function get_warmup_points(cbmodel, v, lbs, ubs; random_objective = false, numstop = 1e10)
+function get_warmup_points(cbm; random_objective = false, numstop = 1e10)
+    v = cbm[:x]
+    ubs = cbm[:ubs]
+    lbs = cbm[:lbs]
     # determine which rxns should be max/min-ized
     fixed_rxns = Int64[]
     for i in eachindex(v)
@@ -30,23 +33,23 @@ function get_warmup_points(cbmodel, v, lbs, ubs; random_objective = false, numst
         i > NN && break
 
         if random_objective
-            @objective(cbmodel, Max, sum(rand() * v[iii] for iii in var_rxn_inds))
+            @objective(cbm, Max, sum(rand() * v[iii] for iii in var_rxn_inds))
         else
-            @objective(cbmodel, Max, v[var_rxn_inds[i]])
+            @objective(cbm, Max, v[var_rxn_inds[i]])
         end
 
-        optimize!(cbmodel)
+        optimize!(cbm)
         for j = 1:size(wpoints, 1)
             wpoints[j, ii] = value(v[j])
         end
 
         if random_objective
-            @objective(cbmodel, Min, sum(rand() * v[iii] for iii in var_rxn_inds))
+            @objective(cbm, Min, sum(rand() * v[iii] for iii in var_rxn_inds))
         else
-            @objective(cbmodel, Min, v[var_rxn_inds[i]])
+            @objective(cbm, Min, v[var_rxn_inds[i]])
         end
 
-        optimize!(cbmodel)
+        optimize!(cbm)
         for j = 1:size(wpoints, 1)
             wpoints[j, ii+1] = value(v[j])
         end
@@ -56,11 +59,13 @@ function get_warmup_points(cbmodel, v, lbs, ubs; random_objective = false, numst
 end
 
 """
-    get_bound_vectors(ubconref, lbconref)
+    get_bound_vectors(opt_model)
 
 Return Float64 vectors of the lower and upper bounds of the JuMP constraint refs.
 """
-function get_bound_vectors(lbconref, ubconref)
+function get_bound_vectors(opt_model)
+    lbconref = opt_model[:lbs]
+    ubconref = opt_model[:ubs]
     lbs = zeros(length(lbconref))
     for i in eachindex(lbs)
         lbval = normalized_rhs(lbconref[i])
@@ -101,25 +106,24 @@ function hit_and_run(
     sense = MOI.MAX_SENSE,
 )
     # get core optimization problem
-    cbmodel, v, mb, lbcons, ubcons =
-        make_optimization_model(model, optimizer, sense = sense)
+    cbm = make_optimization_model(model, optimizer, sense = sense)
+    v = cbm[:x]
 
     if !isempty(solver_attributes) # set other attributes
         for (k, v) in solver_attributes
-            set_optimizer_attribute(cbmodel, k, v)
+            set_optimizer_attribute(cbm, k, v)
         end
     end
 
     # set additional constraints
     for (rxnid, con) in constraints
         ind = model.reactions[findfirst(model.reactions, rxnid)]
-        set_bound(ind, lbcons, ubcons; lb = con[1], ub = con[2])
+        set_bound(ind, cbm; lb = con[1], ub = con[2])
     end
 
-    lbs, ubs = get_bound_vectors(lbcons, ubcons) # get actual ub and lb constraints, can't use model function because the user may have changed them in the function arguments
+    lbs, ubs = get_bound_vectors(cbm) # get actual ub and lb constraints, can't use model function because the user may have changed them in the function arguments
 
-    wpoints =
-        get_warmup_points(cbmodel, v, lbcons, ubcons, random_objective = random_objective)
+    wpoints = get_warmup_points(cbm; random_objective = random_objective)
 
     nwpts = size(wpoints, 2) # number of warmup points generated
     samples = zeros(size(wpoints, 1), samplesize) # sample storage
@@ -233,12 +237,12 @@ function achr(
     solver_attributes = Dict{Any,Any}(),
     random_objective = false,
 )
-    cbmodel, v, _, ubcons, lbcons = build_cbm(model)
+    cbm, v, _, ubcons, lbcons = build_cbm(model)
 
-    set_optimizer(cbmodel, optimizer) # choose optimizer
+    set_optimizer(cbm, optimizer) # choose optimizer
     if !isempty(solver_attributes) # set other attributes
         for (k, v) in solver_attributes
-            set_optimizer_attribute(cbmodel, k, v)
+            set_optimizer_attribute(cbm, k, v)
         end
     end
 
@@ -250,8 +254,7 @@ function achr(
 
     ubs, lbs = get_bound_vectors(ubcons, lbcons) # get actual ub and lb constraints
 
-    wpoints =
-        get_warmup_points(cbmodel, v, ubcons, lbcons, random_objective = random_objective)
+    wpoints = get_warmup_points(cbm, v, ubcons, lbcons, random_objective = random_objective)
 
     nwpts = size(wpoints, 2) # number of warmup points generated
     samples = zeros(size(wpoints, 1), samplesize) # sample storage
diff --git a/test/analysis/fba.jl b/test/analysis/fba.jl
index 3aecc1f119f8183b3f9e2d586668a5e33ed4051a..4e89af7b5cf72bf4813216002029669f6927571c 100644
--- a/test/analysis/fba.jl
+++ b/test/analysis/fba.jl
@@ -1,18 +1,21 @@
 @testset "Flux balance analysis" begin
     cp = test_simpleLP()
-    (lp, x) = flux_balance_analysis(cp, GLPK.Optimizer)
+    lp = flux_balance_analysis(cp, GLPK.Optimizer)
+    x = lp[:x]
     @test termination_status(lp) === MOI.OPTIMAL
     sol = COBREXA.JuMP.value.(x)
     @test sol ≈ [1.0, 2.0]
 
-    (lp, x) = flux_balance_analysis(cp, Clp.Optimizer)
+    lp = flux_balance_analysis(cp, Clp.Optimizer)
+    x = lp[:x]
     @test termination_status(lp) === MOI.OPTIMAL
     sol = COBREXA.JuMP.value.(x)
     @test sol ≈ [1.0, 2.0]
 
     # test the maximization of the objective
     cp = test_simpleLP2()
-    (lp, x) = flux_balance_analysis(cp, GLPK.Optimizer)
+    lp = flux_balance_analysis(cp, GLPK.Optimizer)
+    x = lp[:x]
     @test termination_status(lp) === MOI.OPTIMAL
     sol = COBREXA.JuMP.value.(x)
     @test sol ≈ [-1.0, 2.0]
@@ -27,7 +30,8 @@
     cp = load_model(model_path, "iJR904")
     expected_optimum = 0.9219480950504393
 
-    (lp, x) = flux_balance_analysis(cp, GLPK.Optimizer)
+    lp = flux_balance_analysis(cp, GLPK.Optimizer)
+    x = lp[:x]
     @test termination_status(lp) === MOI.OPTIMAL
     sol = COBREXA.JuMP.value.(x)
     @test objective_value(lp) ≈ expected_optimum
@@ -82,14 +86,16 @@ end
     @test isapprox(producing["atp_c"]["PYK"], 1.75818, atol = 1e-3)
 
     # set bounds
-    cbm, v, mb, lbs, ubs = make_optimization_model(model, optimizer)
+    cbm = make_optimization_model(model, optimizer)
+    ubs = cbm[:ubs]
+    lbs = cbm[:lbs]
     glucose_index = model[findfirst(model.reactions, "EX_glc__D_e")]
     o2_index = model[findfirst(model.reactions, "EX_o2_e")]
     atpm_index = model[findfirst(model.reactions, "ATPM")]
-    set_bound(glucose_index, lbs, ubs; ub = -1.0, lb = -1.0)
+    set_bound(glucose_index, cbm; ub = -1.0, lb = -1.0)
     @test normalized_rhs(ubs[glucose_index]) == -1.0
     @test normalized_rhs(lbs[glucose_index]) == 1.0
-    set_bound(o2_index, lbs, ubs; ub = 1.0, lb = 1.0)
+    set_bound(o2_index, cbm; ub = 1.0, lb = 1.0)
     @test normalized_rhs(ubs[o2_index]) == 1.0
     @test normalized_rhs(lbs[o2_index]) == -1.0
 end
diff --git a/test/base/solver.jl b/test/base/solver.jl
index bcfce612d7af4e263510db5b421b913e9629b2de..5f7f8ab7954e6657fb8cee911e84586d2d61dd30 100644
--- a/test/base/solver.jl
+++ b/test/base/solver.jl
@@ -2,13 +2,15 @@
 @testset "Solve LP" begin
     cp = test_simpleLP()
     optimizer = GLPK.Optimizer
-    (lp, x) = optimize_model(cp, optimizer)
+    lp = optimize_model(cp, optimizer)
+    x = lp[:x]
     @test termination_status(lp) === MOI.OPTIMAL
     sol = COBREXA.JuMP.value.(x)
     @test sol ≈ [1.0, 2.0]
 
     optimizer = Clp.Optimizer
-    (lp, x) = optimize_model(cp, optimizer)
+    lp = optimize_model(cp, optimizer)
+    x = lp[:x]
     @test termination_status(lp) === MOI.OPTIMAL
     sol = COBREXA.JuMP.value.(x)
     @test sol ≈ [1.0, 2.0]