From bb77ce5a29088a1fd7c8d597a2209f377371550d Mon Sep 17 00:00:00 2001 From: Max Resnick Date: Tue, 21 Jun 2022 15:52:32 -0400 Subject: [PATCH 01/12] addded uniswap v3 routing functionality --- src/cfmms.jl | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/src/cfmms.jl b/src/cfmms.jl index d623529..3264664 100644 --- a/src/cfmms.jl +++ b/src/cfmms.jl @@ -190,3 +190,106 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::GeometricMeanTwoCoin{T}, v::VT) where { Λ[2] = geom_arb_λ(v[2]/v[1], R[2], R[1], η, γ) return nothing end + + +struct UniV3{T} <: CFMM{T} + R::Vector{T} + γ::T + Ai::Vector{Int} + current_price :: T + current_tick_index :: Int #This is the index of the maximal tick with price lower than current_price in the ticks dictionary + ticks #This is the tick mapping sorted by price + function UniV3(R,γ,idx,current_price,current_tick_index,ticks) + γ_T, idx_uint, T = two_coin_check_cast(R, γ, idx) + return new{T}( + MVector{2,T}(R), + γ_T, + MVector{2,UInt}(idx_uint), + current_price, + current_tick_index, + ticks + ) + end +end + +## See univ3 whitepaper +function virtual_reserves(P,L) + sP = sqrt(P) + x = L/sP + y = L*sP + return([x, y]) +end +@inline prod_arb_δ(m, r, k, γ) = max(sqrt(γ*m*k) - r, 0)/γ +@inline prod_arb_λ(m, r, k, γ) = max(r - sqrt(k/(m*γ)), 0) +function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:AbstractVector{T}} + current_price, current_tick_index, γ, ticks = cfmm.current_price, cfmm.current_tick_index, cfmm.γ, cfmm.ticks + Δ[1] = 0 + Δ[2] = 0 + + Λ[1] = 0 + Λ[2] = 0 + + target_price = v[2]/v[1] + + if target_price >= current_price #iterate forwards in the tick mapping + i = 1 + while true + next_tick_price = ticks[current_tick_index + i]["price"] + if next_tick_price > target_price ## so now we know that current_price <= target_price < next_tick_price + R = virtual_reserves(max(current_price,ticks[current_tick_index + i - 1]["price"]),ticks[current_tick_index + i - 1]["liquidity"]) + k = R[1]*R[2] + + Δ[1] += prod_arb_δ(target_price, R[1], k, γ) + Δ[2] += prod_arb_δ(1/target_price, R[2], k, γ) + + Λ[1] += prod_arb_λ(1/target_price, R[1], k, γ) + Λ[2] += prod_arb_λ(target_price, R[2], k, γ) + + break + + elseif next_tick_price <= target_price ## so now we know that current_price <= next_tick_price <= target_price + R = virtual_reserves(max(current_price,ticks[current_tick_index + i - 1]["price"]),ticks[current_tick_index + i - 1]["liquidity"]) + k = R[1]*R[2] + + Δ[1] += prod_arb_δ(next_tick_price, R[1], k, γ) + Δ[2] += prod_arb_δ(1/next_tick_price, R[2], k, γ) + + Λ[1] += prod_arb_λ(1/next_tick_price, R[1], k, γ) + Λ[2] += prod_arb_λ(next_tick_price, R[2], k, γ) + end + i += 1 + end + + elseif target_price < current_price #iterate backwards in the tick mapping + i = 1 + while true + prev_tick_price = ticks[current_tick_index - i]["price"] + if prev_tick_price < target_price ## so now we know that prev_tick_price < target_price <= current_price + + R = virtual_reserves(min(current_price,ticks[current_tick_index - i + 1]["price"]),ticks[current_tick_index - i + 1]["liquidity"]) + k = R[1]*R[2] + + Δ[1] += prod_arb_δ(target_price, R[1], k, γ) + Δ[2] += prod_arb_δ(1/target_price, R[2], k, γ) + + Λ[1] += prod_arb_λ(1/target_price, R[1], k, γ) + Λ[2] += prod_arb_λ(target_price, R[2], k, γ) + + break + + elseif prev_tick_price <= target_price ## so now we know that current_price <= next_tick_price <= target_price + R = virtual_reserves(min(current_price,ticks[current_tick_index - i + 1]["price"]),ticks[current_tick_index - i + 1]["liquidity"]) + k = R[1]*R[2] + + Δ[1] += prod_arb_δ(prev_tick_price, R[1], k, γ) + Δ[2] += prod_arb_δ(1/prev_tick_price, R[2], k, γ) + + Λ[1] += prod_arb_λ(1/prev_tick_price, R[1], k, γ) + Λ[2] += prod_arb_λ(prev_tick_price, R[2], k, γ) + end + i += 1 + end + end + return nothing +end + From 7e627ec30262802a236465ba0419e01af45e5a19 Mon Sep 17 00:00:00 2001 From: Max Resnick Date: Tue, 21 Jun 2022 15:55:35 -0400 Subject: [PATCH 02/12] updated the export line to include UniV3 --- src/cfmms.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cfmms.jl b/src/cfmms.jl index 3264664..5175b43 100644 --- a/src/cfmms.jl +++ b/src/cfmms.jl @@ -1,4 +1,4 @@ -export CFMM, ProductTwoCoin, GeometricMeanTwoCoin +export CFMM, ProductTwoCoin, GeometricMeanTwoCoin, UniV3 export find_arb! abstract type CFMM{T} end From d3bfa8819f5c0913c6a2b986a3e207773a1680a0 Mon Sep 17 00:00:00 2001 From: Max Resnick Date: Tue, 21 Jun 2022 16:10:06 -0400 Subject: [PATCH 03/12] removed some stuff that was leftover from my testing --- src/cfmms.jl | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/cfmms.jl b/src/cfmms.jl index 5175b43..b62ea8e 100644 --- a/src/cfmms.jl +++ b/src/cfmms.jl @@ -193,9 +193,7 @@ end struct UniV3{T} <: CFMM{T} - R::Vector{T} - γ::T - Ai::Vector{Int} + @add_two_coin_fields current_price :: T current_tick_index :: Int #This is the index of the maximal tick with price lower than current_price in the ticks dictionary ticks #This is the tick mapping sorted by price @@ -219,8 +217,7 @@ function virtual_reserves(P,L) y = L*sP return([x, y]) end -@inline prod_arb_δ(m, r, k, γ) = max(sqrt(γ*m*k) - r, 0)/γ -@inline prod_arb_λ(m, r, k, γ) = max(r - sqrt(k/(m*γ)), 0) + function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:AbstractVector{T}} current_price, current_tick_index, γ, ticks = cfmm.current_price, cfmm.current_tick_index, cfmm.γ, cfmm.ticks Δ[1] = 0 From f558cf4289d7d8a1050d9045cfe431547dd5fc35 Mon Sep 17 00:00:00 2001 From: Max Resnick Date: Fri, 24 Jun 2022 10:48:30 -0400 Subject: [PATCH 04/12] added an example, still need to add tests --- examples/Univ3.jl | 13 +++++++++++++ src/cfmms.jl | 9 +++++++++ 2 files changed, 22 insertions(+) create mode 100644 examples/Univ3.jl diff --git a/examples/Univ3.jl b/examples/Univ3.jl new file mode 100644 index 0000000..23cb8d2 --- /dev/null +++ b/examples/Univ3.jl @@ -0,0 +1,13 @@ +using CFMMRouter +using LinearAlgebra, SparseArrays, StaticArrays +include("../src/cfmms.jl") + +tick_list = [ Dict("price" => .1, "liquidity" => 1.0), Dict("price" => .5, "liquidity" => 1.0), Dict("price" => 1.0, "liquidity" => 100.0), Dict("price" => 2.0, "liquidity" => 1.0), Dict("price" => 4.0, "liquidity" => 1.0) ] + +pool = UniV3([100,100],1,[1,2],1.0,3,tick_list) +Δ = [0.0,0.0] +Λ = [0.0,0.0] + +find_arb!(Δ,Λ,pool, [1.0,2.0]) + +print((Δ,Λ)) \ No newline at end of file diff --git a/src/cfmms.jl b/src/cfmms.jl index b62ea8e..6f4e294 100644 --- a/src/cfmms.jl +++ b/src/cfmms.jl @@ -1,6 +1,15 @@ export CFMM, ProductTwoCoin, GeometricMeanTwoCoin, UniV3 export find_arb! +#@TODO not sure why i couldnt get this to work without including this macro here +macro def(name, definition) + return quote + macro $(esc(name))() + esc($(Expr(:quote, definition))) + end + end +end + abstract type CFMM{T} end @def add_generic_fields begin From 14f8d4909b52c27d9d36f22171f8454a61072bac Mon Sep 17 00:00:00 2001 From: Max Resnick Date: Mon, 1 Aug 2022 17:23:31 -0700 Subject: [PATCH 05/12] updated fee handling and added some test scaffolding --- src/cfmms.jl | 45 ++++++++++++---------------- test/cfmms.jl | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 26 deletions(-) diff --git a/src/cfmms.jl b/src/cfmms.jl index 6f4e294..2962577 100644 --- a/src/cfmms.jl +++ b/src/cfmms.jl @@ -1,15 +1,6 @@ export CFMM, ProductTwoCoin, GeometricMeanTwoCoin, UniV3 export find_arb! -#@TODO not sure why i couldnt get this to work without including this macro here -macro def(name, definition) - return quote - macro $(esc(name))() - esc($(Expr(:quote, definition))) - end - end -end - abstract type CFMM{T} end @def add_generic_fields begin @@ -235,7 +226,7 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract Λ[1] = 0 Λ[2] = 0 - target_price = v[2]/v[1] + target_price = v[2]/v[1]/γ if target_price >= current_price #iterate forwards in the tick mapping i = 1 @@ -245,11 +236,11 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract R = virtual_reserves(max(current_price,ticks[current_tick_index + i - 1]["price"]),ticks[current_tick_index + i - 1]["liquidity"]) k = R[1]*R[2] - Δ[1] += prod_arb_δ(target_price, R[1], k, γ) - Δ[2] += prod_arb_δ(1/target_price, R[2], k, γ) + Δ[1] += prod_arb_δ(target_price, R[1], k, 1) + Δ[2] += prod_arb_δ(1/target_price, R[2], k, 1) - Λ[1] += prod_arb_λ(1/target_price, R[1], k, γ) - Λ[2] += prod_arb_λ(target_price, R[2], k, γ) + Λ[1] += prod_arb_λ(1/target_price, R[1], k, 1) + Λ[2] += prod_arb_λ(target_price, R[2], k, 1) break @@ -257,11 +248,11 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract R = virtual_reserves(max(current_price,ticks[current_tick_index + i - 1]["price"]),ticks[current_tick_index + i - 1]["liquidity"]) k = R[1]*R[2] - Δ[1] += prod_arb_δ(next_tick_price, R[1], k, γ) - Δ[2] += prod_arb_δ(1/next_tick_price, R[2], k, γ) + Δ[1] += prod_arb_δ(next_tick_price, R[1], k, 1) + Δ[2] += prod_arb_δ(1/next_tick_price, R[2], k, 1) - Λ[1] += prod_arb_λ(1/next_tick_price, R[1], k, γ) - Λ[2] += prod_arb_λ(next_tick_price, R[2], k, γ) + Λ[1] += prod_arb_λ(1/next_tick_price, R[1], k, 1) + Λ[2] += prod_arb_λ(next_tick_price, R[2], k, 1) end i += 1 end @@ -275,11 +266,11 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract R = virtual_reserves(min(current_price,ticks[current_tick_index - i + 1]["price"]),ticks[current_tick_index - i + 1]["liquidity"]) k = R[1]*R[2] - Δ[1] += prod_arb_δ(target_price, R[1], k, γ) - Δ[2] += prod_arb_δ(1/target_price, R[2], k, γ) + Δ[1] += prod_arb_δ(target_price, R[1], k, 1) + Δ[2] += prod_arb_δ(1/target_price, R[2], k, 1) - Λ[1] += prod_arb_λ(1/target_price, R[1], k, γ) - Λ[2] += prod_arb_λ(target_price, R[2], k, γ) + Λ[1] += prod_arb_λ(1/target_price, R[1], k, 1) + Λ[2] += prod_arb_λ(target_price, R[2], k, 1) break @@ -287,15 +278,17 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract R = virtual_reserves(min(current_price,ticks[current_tick_index - i + 1]["price"]),ticks[current_tick_index - i + 1]["liquidity"]) k = R[1]*R[2] - Δ[1] += prod_arb_δ(prev_tick_price, R[1], k, γ) - Δ[2] += prod_arb_δ(1/prev_tick_price, R[2], k, γ) + Δ[1] += prod_arb_δ(prev_tick_price, R[1], k, 1) + Δ[2] += prod_arb_δ(1/prev_tick_price, R[2], k, 1) - Λ[1] += prod_arb_λ(1/prev_tick_price, R[1], k, γ) - Λ[2] += prod_arb_λ(prev_tick_price, R[2], k, γ) + Λ[1] += prod_arb_λ(1/prev_tick_price, R[1], k, 1) + Λ[2] += prod_arb_λ(prev_tick_price, R[2], k, 1) end i += 1 end end + Δ = Δ ./ γ + Λ = Λ ./ γ return nothing end diff --git a/test/cfmms.jl b/test/cfmms.jl index 9b18b12..1fbaf18 100644 --- a/test/cfmms.jl +++ b/test/cfmms.jl @@ -1,5 +1,9 @@ init_opt_cache(R) = (R⁺=similar(R), ∇ϕR = similar(R)) +function returnsTrue() + return true +end + function optimality_conditions_met(c, Δ, Λ, cfmm; cache=nothing) R, γ = cfmm.R, cfmm.γ if isnothing(cache) @@ -20,6 +24,7 @@ function optimality_conditions_met(c, Δ, Λ, cfmm; cache=nothing) opt = maximum(i -> γ * ∇ϕR[i] / c[i], 1:n) ≤ minimum(i -> ∇ϕR[i] / c[i], 1:n) + sqrt(eps()) return pfeas && cfmm_sat && opt end + @testset "CFMMs" begin @testset "arbitrage checks: two coins" begin Δ = MVector{2, Float64}(undef) @@ -70,6 +75,84 @@ end @test optimality_conditions_met(ν, Δ, Λ, cfmm; cache=cache) end end + + @testset "univ3" begin + #reserves dont matter for univ3 pools, only tick data so just setting to 1 + R = [1,1] + #no fees for now + γ = 1 + # + ids = [1,2] + current_price = 15 + current_tick_index = 2 + ticks = [Dict("price" => 5, "liquidity => 1"), Dict("price" => 10, "liquidity" => 2), Dict("price" => 20, "liquidity" => 1)] + cfmm = UniV3(R,γ,ids, current_price, current_tick_index, ticks) + + Δ = [0,0] + Λ = [0,0] + v = [1,15] + find_arb!(Δ,Λ,cfmm,v) + @test true + @test true + + current_price = 15 + current_tick_index = 2 + ticks = [Dict("price" => 5, "liquidity => 1"), Dict("price" => 10, "liquidity" => 2), Dict("price" => 20, "liquidity" => 1)] + cfmm = UniV3(R,γ,ids, current_price, current_tick_index, ticks) + + Δ = [0,0] + Λ = [0,0] + v = [1,15] + find_arb!(Δ,Λ,cfmm,v) + @test true + + + current_price = 15 + current_tick_index = 2 + ticks = [Dict("price" => 5, "liquidity => 1"), Dict("price" => 10, "liquidity" => 2), Dict("price" => 20, "liquidity" => 1)] + cfmm = UniV3(R,γ,ids, current_price, current_tick_index, ticks) + + Δ = [0,0] + Λ = [0,0] + v = [1,15] + find_arb!(Δ,Λ,cfmm,v) + @test returnsTrue() + + + current_price = 15 + current_tick_index = 2 + ticks = [Dict("price" => 5, "liquidity => 1"), Dict("price" => 10, "liquidity" => 2), Dict("price" => 20, "liquidity" => 1)] + cfmm = UniV3(R,γ,ids, current_price, current_tick_index, ticks) + + Δ = [0,0] + Λ = [0,0] + v = [1,15] + find_arb!(Δ,Λ,cfmm,v) + @test true + + + current_price = 15 + current_tick_index = 2 + ticks = [Dict("price" => 5, "liquidity => 1"), Dict("price" => 10, "liquidity" => 2), Dict("price" => 20, "liquidity" => 1)] + cfmm = UniV3(R,γ,ids, current_price, current_tick_index, ticks) + + Δ = [0,0] + Λ = [0,0] + v = [1,15] + find_arb!(Δ,Λ,cfmm,v) + @test true + + current_price = 15 + current_tick_index = 2 + ticks = [Dict("price" => 5, "liquidity => 1"), Dict("price" => 10, "liquidity" => 2), Dict("price" => 20, "liquidity" => 1)] + cfmm = UniV3(R,γ,ids, current_price, current_tick_index, ticks) + + Δ = [0,0] + Λ = [0,0] + v = [1,15] + find_arb!(Δ,Λ,cfmm,v) + @test true + end end end \ No newline at end of file From a56a6bc24f335457885014ca55b7351b607aa785 Mon Sep 17 00:00:00 2001 From: Max Resnick Date: Mon, 8 Aug 2022 18:56:35 -0700 Subject: [PATCH 06/12] testing finished up for the no fee case, fee case is still off a bit --- src/cfmms.jl | 52 ++++++------ test/cfmms.jl | 222 ++++++++++++++++++++++++++++++++------------------ 2 files changed, 169 insertions(+), 105 deletions(-) diff --git a/src/cfmms.jl b/src/cfmms.jl index 2962577..a20d141 100644 --- a/src/cfmms.jl +++ b/src/cfmms.jl @@ -226,33 +226,35 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract Λ[1] = 0 Λ[2] = 0 - target_price = v[2]/v[1]/γ + target_price = max(min(v[1]/v[2]/γ,2.0^64),1/2.0^64) #including out of bounds check here if target_price >= current_price #iterate forwards in the tick mapping i = 1 while true next_tick_price = ticks[current_tick_index + i]["price"] - if next_tick_price > target_price ## so now we know that current_price <= target_price < next_tick_price + if next_tick_price >= target_price ## so now we know that current_price <= target_price < next_tick_price + #print(max(current_price,ticks[current_tick_index + i - 1]["price"])) R = virtual_reserves(max(current_price,ticks[current_tick_index + i - 1]["price"]),ticks[current_tick_index + i - 1]["liquidity"]) + #print(R[2]/R[1]) k = R[1]*R[2] - Δ[1] += prod_arb_δ(target_price, R[1], k, 1) - Δ[2] += prod_arb_δ(1/target_price, R[2], k, 1) + Δ[1] += prod_arb_δ(1/target_price, R[1], k, 1) + Δ[2] += prod_arb_δ(target_price, R[2], k, 1) - Λ[1] += prod_arb_λ(1/target_price, R[1], k, 1) - Λ[2] += prod_arb_λ(target_price, R[2], k, 1) + Λ[1] += prod_arb_λ(target_price, R[1], k, 1) + Λ[2] += prod_arb_λ(1/target_price, R[2], k, 1) break - elseif next_tick_price <= target_price ## so now we know that current_price <= next_tick_price <= target_price + elseif next_tick_price < target_price ## so now we know that current_price <= next_tick_price <= target_price R = virtual_reserves(max(current_price,ticks[current_tick_index + i - 1]["price"]),ticks[current_tick_index + i - 1]["liquidity"]) k = R[1]*R[2] - Δ[1] += prod_arb_δ(next_tick_price, R[1], k, 1) - Δ[2] += prod_arb_δ(1/next_tick_price, R[2], k, 1) + Δ[1] += prod_arb_δ(1/next_tick_price, R[1], k, 1) + Δ[2] += prod_arb_δ(next_tick_price, R[2], k, 1) - Λ[1] += prod_arb_λ(1/next_tick_price, R[1], k, 1) - Λ[2] += prod_arb_λ(next_tick_price, R[2], k, 1) + Λ[1] += prod_arb_λ(next_tick_price, R[1], k, 1) + Λ[2] += prod_arb_λ(1/next_tick_price, R[2], k, 1) end i += 1 end @@ -260,29 +262,31 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract elseif target_price < current_price #iterate backwards in the tick mapping i = 1 while true - prev_tick_price = ticks[current_tick_index - i]["price"] - if prev_tick_price < target_price ## so now we know that prev_tick_price < target_price <= current_price + prev_tick_price = ticks[current_tick_index - i + 1]["price"] + if prev_tick_price <= target_price ## so now we know that prev_tick_price < target_price <= current_price - R = virtual_reserves(min(current_price,ticks[current_tick_index - i + 1]["price"]),ticks[current_tick_index - i + 1]["liquidity"]) + print(ticks[current_tick_index - i + 2]["price"]) + R = virtual_reserves(min(current_price,ticks[current_tick_index - i + 2]["price"]),ticks[current_tick_index - i + 1]["liquidity"]) k = R[1]*R[2] - Δ[1] += prod_arb_δ(target_price, R[1], k, 1) - Δ[2] += prod_arb_δ(1/target_price, R[2], k, 1) + Δ[1] += prod_arb_δ(1/target_price, R[1], k, 1) + Δ[2] += prod_arb_δ(target_price, R[2], k, 1) - Λ[1] += prod_arb_λ(1/target_price, R[1], k, 1) - Λ[2] += prod_arb_λ(target_price, R[2], k, 1) + Λ[1] += prod_arb_λ(target_price, R[1], k, 1) + Λ[2] += prod_arb_λ(1/target_price, R[2], k, 1) break - elseif prev_tick_price <= target_price ## so now we know that current_price <= next_tick_price <= target_price - R = virtual_reserves(min(current_price,ticks[current_tick_index - i + 1]["price"]),ticks[current_tick_index - i + 1]["liquidity"]) + elseif prev_tick_price > target_price ## so now we know that current_price <= next_tick_price <= target_price + + R = virtual_reserves(min(current_price,ticks[current_tick_index - i + 2]["price"]),ticks[current_tick_index - i + 1]["liquidity"]) k = R[1]*R[2] - Δ[1] += prod_arb_δ(prev_tick_price, R[1], k, 1) - Δ[2] += prod_arb_δ(1/prev_tick_price, R[2], k, 1) + Δ[1] += prod_arb_δ(1/prev_tick_price, R[1], k, 1) + Δ[2] += prod_arb_δ(prev_tick_price, R[2], k, 1) - Λ[1] += prod_arb_λ(1/prev_tick_price, R[1], k, 1) - Λ[2] += prod_arb_λ(prev_tick_price, R[2], k, 1) + Λ[1] += prod_arb_λ(prev_tick_price, R[1], k, 1) + Λ[2] += prod_arb_λ(1/prev_tick_price, R[2], k, 1) end i += 1 end diff --git a/test/cfmms.jl b/test/cfmms.jl index 1fbaf18..28c863b 100644 --- a/test/cfmms.jl +++ b/test/cfmms.jl @@ -1,9 +1,5 @@ init_opt_cache(R) = (R⁺=similar(R), ∇ϕR = similar(R)) -function returnsTrue() - return true -end - function optimality_conditions_met(c, Δ, Λ, cfmm; cache=nothing) R, γ = cfmm.R, cfmm.γ if isnothing(cache) @@ -76,83 +72,147 @@ end end end - @testset "univ3" begin - #reserves dont matter for univ3 pools, only tick data so just setting to 1 - R = [1,1] - #no fees for now - γ = 1 - # - ids = [1,2] - current_price = 15 - current_tick_index = 2 - ticks = [Dict("price" => 5, "liquidity => 1"), Dict("price" => 10, "liquidity" => 2), Dict("price" => 20, "liquidity" => 1)] - cfmm = UniV3(R,γ,ids, current_price, current_tick_index, ticks) - - Δ = [0,0] - Λ = [0,0] - v = [1,15] - find_arb!(Δ,Λ,cfmm,v) - @test true - @test true - - current_price = 15 - current_tick_index = 2 - ticks = [Dict("price" => 5, "liquidity => 1"), Dict("price" => 10, "liquidity" => 2), Dict("price" => 20, "liquidity" => 1)] - cfmm = UniV3(R,γ,ids, current_price, current_tick_index, ticks) - - Δ = [0,0] - Λ = [0,0] - v = [1,15] - find_arb!(Δ,Λ,cfmm,v) - @test true - - - current_price = 15 - current_tick_index = 2 - ticks = [Dict("price" => 5, "liquidity => 1"), Dict("price" => 10, "liquidity" => 2), Dict("price" => 20, "liquidity" => 1)] - cfmm = UniV3(R,γ,ids, current_price, current_tick_index, ticks) - - Δ = [0,0] - Λ = [0,0] - v = [1,15] - find_arb!(Δ,Λ,cfmm,v) - @test returnsTrue() - - - current_price = 15 - current_tick_index = 2 - ticks = [Dict("price" => 5, "liquidity => 1"), Dict("price" => 10, "liquidity" => 2), Dict("price" => 20, "liquidity" => 1)] - cfmm = UniV3(R,γ,ids, current_price, current_tick_index, ticks) - - Δ = [0,0] - Λ = [0,0] - v = [1,15] - find_arb!(Δ,Λ,cfmm,v) - @test true - - - current_price = 15 - current_tick_index = 2 - ticks = [Dict("price" => 5, "liquidity => 1"), Dict("price" => 10, "liquidity" => 2), Dict("price" => 20, "liquidity" => 1)] - cfmm = UniV3(R,γ,ids, current_price, current_tick_index, ticks) - - Δ = [0,0] - Λ = [0,0] - v = [1,15] - find_arb!(Δ,Λ,cfmm,v) - @test true - - current_price = 15 - current_tick_index = 2 - ticks = [Dict("price" => 5, "liquidity => 1"), Dict("price" => 10, "liquidity" => 2), Dict("price" => 20, "liquidity" => 1)] - cfmm = UniV3(R,γ,ids, current_price, current_tick_index, ticks) - - Δ = [0,0] - Λ = [0,0] - v = [1,15] - find_arb!(Δ,Λ,cfmm,v) - @test true - end + +end end +@testset "univ3" begin + + + #this test is going to be one were there is no arbitrage because the current_price = target_price + #there can be some slight numerical error when calculating virtual_reserves + + # #reserves dont matter for univ3 pools, only tick data so just setting to 1 + R = [1.0,1.0] + # #no fees for now + γ = 1 + # # + ids = [1.0,2.0] + current_price = 15.0 + current_tick_index = 3.0 + ticks = [Dict("price" => 1/2.0^64, "liquidity" => 0.0),Dict("price" => 5.0, "liquidity" => 1.0), Dict("price" => 10.0, "liquidity" => 2.0), Dict("price" => 20.0, "liquidity" => 1.0), Dict("price" => 30.0, "liquidity" => 0.0), Dict("price" => 2.0^64, "liquidity" => 0)] + cfmm = UniV3(R,γ,ids, current_price, current_tick_index, ticks) + + Δ = [0.0,0.0] + Λ = [0.0,0.0] + v = [15.0,1.0] + find_arb!(Δ,Λ,cfmm,v) + + @test (norm(Δ) <= 1e-12) && (norm(Λ) <= 1e-12) #nothing happens + + + #In this test the target price is higher than the current_price but we are still within one tick + + Δ = [0.0,0.0] + Λ = [0.0,0.0] + v = [18.0,1.0] + find_arb!(Δ,Λ,cfmm,v) + + @test (Δ[1] == 0) # no token 0 in + @test (Δ[2] > 0) # posiive token 1 in + @test (Λ[1] > 0) # positive token 0 out + @test (Λ[2] == 0) # no token 1 out + @test (16 <= Δ[2]/Λ[1]) && (Δ[2]/Λ[1] <= 17) #Average Price paid is between 16 and 17 + + + # now we cross a tick going up + + Δ = [0.0,0.0] + Λ = [0.0,0.0] + v = [22.0,1.0] + find_arb!(Δ,Λ,cfmm,v) + + @test (Δ[1] == 0) # no token 0 in + @test (Δ[2] > 0) # posiive token 1 in + @test (Λ[1] > 0) # positive token 0 out + @test (Λ[2] == 0) # no token 1 out + + @test (17 <= Δ[2]/Λ[1]) && (Δ[2]/Λ[1] <= 18) #Average Price paid is between 17 and 18 + + + #out of bounds test upper + Δ = [0.0,0.0] + Λ = [0.0,0.0] + v = [29.99,1.0] + find_arb!(Δ,Λ,cfmm,v) + + @test (Δ[1] == 0) # no token 0 in + @test (Δ[2] > 0) # posiive token 1 in + @test (Λ[1] > 0) # positive token 0 out + @test (Λ[2] == 0) # no token 1 out + + + @test (19.5 <= Δ[2]/Λ[1]) && (Δ[2]/Λ[1] <= 20.5) + + Δ = [0.0,0.0] + Λ = [0.0,0.0] + v = [35,1.0] + find_arb!(Δ,Λ,cfmm,v) + + @test (Δ[1] == 0) # no token 0 in + @test (Δ[2] > 0) # posiive token 1 in + @test (Λ[1] > 0) # positive token 0 out + @test (Λ[2] == 0) # no token 1 out + + @test (19.5 <= Δ[2]/Λ[1]) && (Δ[2]/Λ[1] <= 20.5) + + + #Now we test when target price is below current price but within current tick + + #starting with just below current price + Δ = [0.0,0.0] + Λ = [0.0,0.0] + v = [14.99999,1.0] #basically current price but less than so we check the other branch + find_arb!(Δ,Λ,cfmm,v) + + + + @test (norm(Δ) <= 1e-3) && (norm(Λ) <= 1e-3) #nothing happens + + + #now below current price but not below current tick price + + Δ = [0.0,0.0] + Λ = [0.0,0.0] + v = [12.0,1.0] + find_arb!(Δ,Λ,cfmm,v) + + @test (Δ[1] > 0) # positive token 0 in + @test (Δ[2] == 0) # no token 1 in + @test (Λ[1] == 0) # no 0 out + @test (Λ[2] > 0) # positive 1 out + + @test (13 <= Λ[2]/Δ[1]) && (Λ[2]/Δ[1] <= 14) #Average Price paid is between 13 and 14 + + #now below current price and crossing a tick + + Δ = [0.0,0.0] + Λ = [0.0,0.0] + v = [5.01,1.0] + find_arb!(Δ,Λ,cfmm,v) + + + @test (Δ[1] > 0) # positive token 0 in + @test (Δ[2] == 0) # no token 1 in + @test (Λ[1] == 0) # no 0 out + @test (Λ[2] > 0) # positive 1 out + + @test (9 <= Λ[2]/Δ[1]) && (Λ[2]/Δ[1] <= 10) #Average Price paid is between 9 and 10 + + #now out of bounds test + + Δ = [0.0,0.0] + Λ = [0.0,0.0] + v = [4.0,1.0] + find_arb!(Δ,Λ,cfmm,v) + + + @test (Δ[1] > 0) # positive token 0 in + @test (Δ[2] == 0) # no token 1 in + @test (Λ[1] == 0) # no 0 out + @test (Λ[2] > 0) # positive 1 out + + @test (9 <= Λ[2]/Δ[1]) && (Λ[2]/Δ[1] <= 10) #Average Price paid is between 13 and 14 + + end \ No newline at end of file From c08d97cc53b10eca5fff0b84b0be9c2f39467b4f Mon Sep 17 00:00:00 2001 From: Max Resnick Date: Wed, 10 Aug 2022 13:09:23 -0700 Subject: [PATCH 07/12] added no arb interval so fees are working now --- src/cfmms.jl | 8 ++++++-- test/cfmms.jl | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/cfmms.jl b/src/cfmms.jl index a20d141..8a0e94c 100644 --- a/src/cfmms.jl +++ b/src/cfmms.jl @@ -226,8 +226,12 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract Λ[1] = 0 Λ[2] = 0 - target_price = max(min(v[1]/v[2]/γ,2.0^64),1/2.0^64) #including out of bounds check here - + #target_price = max(min(v[1]/v[2]/γ,2.0^64),1/2.0^64) #including out of bounds check here + target_price = v[1]/v[2] + if (target_price*γ < current_price) && (current_price < target_price * 1/(γ)) + return nothing + end + target_price = target_price/γ if target_price >= current_price #iterate forwards in the tick mapping i = 1 while true diff --git a/test/cfmms.jl b/test/cfmms.jl index 28c863b..a1d55d4 100644 --- a/test/cfmms.jl +++ b/test/cfmms.jl @@ -84,7 +84,7 @@ end # #reserves dont matter for univ3 pools, only tick data so just setting to 1 R = [1.0,1.0] # #no fees for now - γ = 1 + γ = .997 # # ids = [1.0,2.0] current_price = 15.0 From 1900e74198f0ab8b5cc673d3009f5b76b403bda6 Mon Sep 17 00:00:00 2001 From: Max Resnick Date: Wed, 24 Aug 2022 14:21:59 -0700 Subject: [PATCH 08/12] adressed PR coments and added update_reserves functionality --- examples/Univ3.jl | 22 +++++++++++++++++++--- src/cfmms.jl | 42 ++++++++++++++++++++++++++++++++++++------ src/router.jl | 3 +-- test/cfmms.jl | 22 +++++++++++++++++++--- 4 files changed, 75 insertions(+), 14 deletions(-) diff --git a/examples/Univ3.jl b/examples/Univ3.jl index 23cb8d2..916bc22 100644 --- a/examples/Univ3.jl +++ b/examples/Univ3.jl @@ -1,8 +1,19 @@ using CFMMRouter using LinearAlgebra, SparseArrays, StaticArrays -include("../src/cfmms.jl") -tick_list = [ Dict("price" => .1, "liquidity" => 1.0), Dict("price" => .5, "liquidity" => 1.0), Dict("price" => 1.0, "liquidity" => 100.0), Dict("price" => 2.0, "liquidity" => 1.0), Dict("price" => 4.0, "liquidity" => 1.0) ] + +#The price in each tick refers to the lower bound on the interval +#so the intervals are [t_i,t_i+1] with liquidity L_i +# p2--------- +# p1------ | p3------- +# | | | +# L1 L2 L3 +# | | | +tick_list = [Dict("price" => .1, "liquidity" => 1.0), + Dict("price" => .5, "liquidity" => 1.0), + Dict("price" => 1.0, "liquidity" => 100.0), + Dict("price" => 2.0, "liquidity" => 1.0), + Dict("price" => 4.0, "liquidity" => 1.0)] pool = UniV3([100,100],1,[1,2],1.0,3,tick_list) Δ = [0.0,0.0] @@ -10,4 +21,9 @@ pool = UniV3([100,100],1,[1,2],1.0,3,tick_list) find_arb!(Δ,Λ,pool, [1.0,2.0]) -print((Δ,Λ)) \ No newline at end of file +print(Δ,Λ) + +update_reserves!(pool, Δ, Λ, [1.0,2.0]) + +print(pool.current_price, pool.current_tick_index) + diff --git a/src/cfmms.jl b/src/cfmms.jl index 8a0e94c..0240f9f 100644 --- a/src/cfmms.jl +++ b/src/cfmms.jl @@ -1,5 +1,6 @@ export CFMM, ProductTwoCoin, GeometricMeanTwoCoin, UniV3 export find_arb! +export update_reserves! abstract type CFMM{T} end @@ -192,7 +193,15 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::GeometricMeanTwoCoin{T}, v::VT) where { end -struct UniV3{T} <: CFMM{T} +#The price in each tick refers to the lower bound on the interval +#so the intervals are [t_i,t_i+1] with liquidity L_i +# p2--------- +# p1------ | p3------- +# | | | +# L1 L2 L3 +# | | | + +mutable struct UniV3{T} <: CFMM{T} @add_two_coin_fields current_price :: T current_tick_index :: Int #This is the index of the maximal tick with price lower than current_price in the ticks dictionary @@ -215,7 +224,7 @@ function virtual_reserves(P,L) sP = sqrt(P) x = L/sP y = L*sP - return([x, y]) + return x,y end function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:AbstractVector{T}} @@ -237,9 +246,11 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract while true next_tick_price = ticks[current_tick_index + i]["price"] if next_tick_price >= target_price ## so now we know that current_price <= target_price < next_tick_price - #print(max(current_price,ticks[current_tick_index + i - 1]["price"])) - R = virtual_reserves(max(current_price,ticks[current_tick_index + i - 1]["price"]),ticks[current_tick_index + i - 1]["liquidity"]) - #print(R[2]/R[1]) + R = virtual_reserves( + max(current_price,ticks[current_tick_index + i - 1]["price"]), + ticks[current_tick_index + i - 1]["liquidity"] + ) + k = R[1]*R[2] Δ[1] += prod_arb_δ(1/target_price, R[1], k, 1) @@ -269,7 +280,6 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract prev_tick_price = ticks[current_tick_index - i + 1]["price"] if prev_tick_price <= target_price ## so now we know that prev_tick_price < target_price <= current_price - print(ticks[current_tick_index - i + 2]["price"]) R = virtual_reserves(min(current_price,ticks[current_tick_index - i + 2]["price"]),ticks[current_tick_index - i + 1]["liquidity"]) k = R[1]*R[2] @@ -300,3 +310,23 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract return nothing end +function update_reserves!(c :: CFMM, Δ, Λ, V) + c.R .+= Δ - Λ +end + +function update_reserves!(c :: UniV3, Δ, Λ, V) + c.R .+= Δ - Λ #update reserves + + if any(Δ .!= 0) || any(Λ .!= 0) #current_tick & current_price only if outside the no arb interval + target_price = V[1]/V[2] + c.current_price = target_price + + #there are much more efficient ways to do this e.g. binary search but this should work for now + for i in eachindex(c.ticks) + if (c.ticks[i]["price"]<= c.current_price) & (c.current_price < c.ticks[i+1]["price"]) + c.current_tick_index = i + break + end + end + end +end \ No newline at end of file diff --git a/src/router.jl b/src/router.jl index ed722db..c3916ec 100644 --- a/src/router.jl +++ b/src/router.jl @@ -127,8 +127,7 @@ end function update_reserves!(r::Router) for (Δ, Λ, c) in zip(r.Δs, r.Λs, r.cfmms) - c.R .+= Δ - Λ + update_reserves!(c, Δ,Λ,r.v[c.Ai]) end - return nothing end diff --git a/test/cfmms.jl b/test/cfmms.jl index a1d55d4..fb1225f 100644 --- a/test/cfmms.jl +++ b/test/cfmms.jl @@ -89,7 +89,13 @@ end ids = [1.0,2.0] current_price = 15.0 current_tick_index = 3.0 - ticks = [Dict("price" => 1/2.0^64, "liquidity" => 0.0),Dict("price" => 5.0, "liquidity" => 1.0), Dict("price" => 10.0, "liquidity" => 2.0), Dict("price" => 20.0, "liquidity" => 1.0), Dict("price" => 30.0, "liquidity" => 0.0), Dict("price" => 2.0^64, "liquidity" => 0)] + ticks = [Dict("price" => 1/2.0^64,"liquidity" => 0.0), + Dict("price" => 5.0,"liquidity" => 1.0), + Dict("price" => 10.0, "liquidity" => 2.0), + Dict("price" => 20.0, "liquidity" => 1.0), + Dict("price" => 30.0, "liquidity" => 0.0), + Dict("price" => 2.0^64, "liquidity" => 0)] + cfmm = UniV3(R,γ,ids, current_price, current_tick_index, ticks) Δ = [0.0,0.0] @@ -113,7 +119,6 @@ end @test (Λ[2] == 0) # no token 1 out @test (16 <= Δ[2]/Λ[1]) && (Δ[2]/Λ[1] <= 17) #Average Price paid is between 16 and 17 - # now we cross a tick going up Δ = [0.0,0.0] @@ -214,5 +219,16 @@ end @test (9 <= Λ[2]/Δ[1]) && (Λ[2]/Δ[1] <= 10) #Average Price paid is between 13 and 14 - + + #update_reserves for univ3 test + Δ = [0.0,0.0] + Λ = [0.0,0.0] + v = [18.0,1.0] + find_arb!(Δ,Λ,cfmm,v) + + update_reserves!(cfmm, Δ, Λ, v) + + @test (cfmm.current_price == 18.0) + @test (cfmm.current_tick_index == 3) + end \ No newline at end of file From 1e96c0611d003e378e8d524ced1bc3ecc8bcfb68 Mon Sep 17 00:00:00 2001 From: Max-RiskHarbor <89545638+Max-RiskHarbor@users.noreply.github.com> Date: Mon, 17 Oct 2022 11:30:06 -0700 Subject: [PATCH 09/12] unfuck docs and add edge case handling for running out of liquidity in Univ3 --- examples/Univ3.jl | 18 ++++++++++-------- src/cfmms.jl | 16 ++++++++++++++-- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/examples/Univ3.jl b/examples/Univ3.jl index 916bc22..6c4f059 100644 --- a/examples/Univ3.jl +++ b/examples/Univ3.jl @@ -1,14 +1,16 @@ +#= +# Uniswap V3 Router +This example illustrates how to setup uniswapv3 pools +=# + using CFMMRouter using LinearAlgebra, SparseArrays, StaticArrays +#= + The price in each tick refers to the lower bound on the interval + so the intervals are [t_i,t_i+1] with liquidity L_i +=# -#The price in each tick refers to the lower bound on the interval -#so the intervals are [t_i,t_i+1] with liquidity L_i -# p2--------- -# p1------ | p3------- -# | | | -# L1 L2 L3 -# | | | tick_list = [Dict("price" => .1, "liquidity" => 1.0), Dict("price" => .5, "liquidity" => 1.0), Dict("price" => 1.0, "liquidity" => 100.0), @@ -25,5 +27,5 @@ print(Δ,Λ) update_reserves!(pool, Δ, Λ, [1.0,2.0]) -print(pool.current_price, pool.current_tick_index) +println(pool.current_price, pool.current_tick_index) diff --git a/src/cfmms.jl b/src/cfmms.jl index 0240f9f..03f8ece 100644 --- a/src/cfmms.jl +++ b/src/cfmms.jl @@ -244,7 +244,13 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract if target_price >= current_price #iterate forwards in the tick mapping i = 1 while true - next_tick_price = ticks[current_tick_index + i]["price"] + next_tick_price = 0.0 + try + next_tick_price = ticks[current_tick_index + i]["price"] + catch + ## Ran out of liquidity + break + end if next_tick_price >= target_price ## so now we know that current_price <= target_price < next_tick_price R = virtual_reserves( max(current_price,ticks[current_tick_index + i - 1]["price"]), @@ -277,7 +283,13 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract elseif target_price < current_price #iterate backwards in the tick mapping i = 1 while true - prev_tick_price = ticks[current_tick_index - i + 1]["price"] + prev_tick_price = 0.0 + try + prev_tick_price = ticks[current_tick_index - i + 1]["price"] + catch + ## Ran out of liquidity + break + end if prev_tick_price <= target_price ## so now we know that prev_tick_price < target_price <= current_price R = virtual_reserves(min(current_price,ticks[current_tick_index - i + 2]["price"]),ticks[current_tick_index - i + 1]["liquidity"]) From e5e6075beeb60eb78eadf222f739209f69aaf144 Mon Sep 17 00:00:00 2001 From: Max-RiskHarbor <89545638+Max-RiskHarbor@users.noreply.github.com> Date: Wed, 19 Oct 2022 08:23:54 -0700 Subject: [PATCH 10/12] fixed another edge case and fixed bug with basket liquidation error --- src/cfmms.jl | 20 ++++++++++++++------ src/objectives.jl | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/cfmms.jl b/src/cfmms.jl index 03f8ece..28b4448 100644 --- a/src/cfmms.jl +++ b/src/cfmms.jl @@ -287,12 +287,16 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract try prev_tick_price = ticks[current_tick_index - i + 1]["price"] catch - ## Ran out of liquidity - break + # Ran out of liquidity + break end if prev_tick_price <= target_price ## so now we know that prev_tick_price < target_price <= current_price - - R = virtual_reserves(min(current_price,ticks[current_tick_index - i + 2]["price"]),ticks[current_tick_index - i + 1]["liquidity"]) + R = [0.0,0.0] + try #it can happen that we are beyond the last tick and then this will have an indexing error in which case there is no liquidity + R = virtual_reserves(min(current_price,ticks[current_tick_index - i + 2]["price"]),ticks[current_tick_index - i + 1]["liquidity"]) + catch + break + end k = R[1]*R[2] Δ[1] += prod_arb_δ(1/target_price, R[1], k, 1) @@ -304,8 +308,12 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract break elseif prev_tick_price > target_price ## so now we know that current_price <= next_tick_price <= target_price - - R = virtual_reserves(min(current_price,ticks[current_tick_index - i + 2]["price"]),ticks[current_tick_index - i + 1]["liquidity"]) + R = [0.0,0.0] + try #it can happen that we are beyond the last tick and then this will have an indexing error error in which case there is no liquidity + R = virtual_reserves(min(current_price,ticks[current_tick_index - i + 2]["price"]),ticks[current_tick_index - i + 1]["liquidity"]) + catch + break + end k = R[1]*R[2] Δ[1] += prod_arb_δ(1/prev_tick_price, R[1], k, 1) diff --git a/src/objectives.jl b/src/objectives.jl index 2f16e9b..08a6da1 100644 --- a/src/objectives.jl +++ b/src/objectives.jl @@ -94,7 +94,7 @@ struct BasketLiquidation{T} <: Objective Δin::Vector{T} function BasketLiquidation(i::Integer, Δin::Vector{T}) where {T<:AbstractFloat} - !(i > 0 && i < length(Δin)) && throw(ArgumentError("Invalid index i")) + !(i > 0 && i <= length(Δin)) && throw(ArgumentError("Invalid index i")) return new{T}( i, Δin, From 7a469a3040a08e3c66a9d993dda8b987cff96662 Mon Sep 17 00:00:00 2001 From: Max-RiskHarbor <89545638+Max-RiskHarbor@users.noreply.github.com> Date: Wed, 19 Oct 2022 21:37:28 -0700 Subject: [PATCH 11/12] this is the version that works for the simulations --- src/cfmms.jl | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/cfmms.jl b/src/cfmms.jl index 28b4448..ab63a3a 100644 --- a/src/cfmms.jl +++ b/src/cfmms.jl @@ -235,12 +235,11 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract Λ[1] = 0 Λ[2] = 0 - #target_price = max(min(v[1]/v[2]/γ,2.0^64),1/2.0^64) #including out of bounds check here target_price = v[1]/v[2] - if (target_price*γ < current_price) && (current_price < target_price * 1/(γ)) - return nothing - end - target_price = target_price/γ + # if (current_price*γ < target_price) && (target_price < current_price * 1/(γ)) + # return nothing + # end + #target_price = target_price/γ if target_price >= current_price #iterate forwards in the tick mapping i = 1 while true @@ -292,7 +291,7 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract end if prev_tick_price <= target_price ## so now we know that prev_tick_price < target_price <= current_price R = [0.0,0.0] - try #it can happen that we are beyond the last tick and then this will have an indexing error in which case there is no liquidity + try #it can happen that we are beyond the last tick and then this will have an indexing error in which case there is no liquid R = virtual_reserves(min(current_price,ticks[current_tick_index - i + 2]["price"]),ticks[current_tick_index - i + 1]["liquidity"]) catch break @@ -309,7 +308,7 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract elseif prev_tick_price > target_price ## so now we know that current_price <= next_tick_price <= target_price R = [0.0,0.0] - try #it can happen that we are beyond the last tick and then this will have an indexing error error in which case there is no liquidity + try #it can happen that we are beyond the last tick and then this will have an indexing error R = virtual_reserves(min(current_price,ticks[current_tick_index - i + 2]["price"]),ticks[current_tick_index - i + 1]["liquidity"]) catch break @@ -325,8 +324,8 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract i += 1 end end - Δ = Δ ./ γ - Λ = Λ ./ γ + #Δ = Δ ./ γ + #Λ = Λ ./ γ return nothing end From a83c83836e3273cc22c8e4721e4602bf1070b1f6 Mon Sep 17 00:00:00 2001 From: Max-RiskHarbor <89545638+Max-RiskHarbor@users.noreply.github.com> Date: Wed, 19 Oct 2022 21:46:28 -0700 Subject: [PATCH 12/12] fix merge conflicts --- src/cfmms.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cfmms.jl b/src/cfmms.jl index ab63a3a..67b09e2 100644 --- a/src/cfmms.jl +++ b/src/cfmms.jl @@ -291,7 +291,7 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract end if prev_tick_price <= target_price ## so now we know that prev_tick_price < target_price <= current_price R = [0.0,0.0] - try #it can happen that we are beyond the last tick and then this will have an indexing error in which case there is no liquid + try #it can happen that we are beyond the last tick and then this will have an indexing error in which case there is no liquidity R = virtual_reserves(min(current_price,ticks[current_tick_index - i + 2]["price"]),ticks[current_tick_index - i + 1]["liquidity"]) catch break @@ -308,7 +308,7 @@ function find_arb!(Δ::VT, Λ::VT, cfmm::UniV3{T}, v::VT) where {T, VT<:Abstract elseif prev_tick_price > target_price ## so now we know that current_price <= next_tick_price <= target_price R = [0.0,0.0] - try #it can happen that we are beyond the last tick and then this will have an indexing error + try #it can happen that we are beyond the last tick and then this will have an indexing error error in which case there is no liquidity R = virtual_reserves(min(current_price,ticks[current_tick_index - i + 2]["price"]),ticks[current_tick_index - i + 1]["liquidity"]) catch break