Current section

8 Versions

Jump to

Compare versions

7 files changed
+56 additions
-20 deletions
  @@ -1,7 +1,7 @@
1 1 {<<"links">>,
2 2 [{<<"GitHub">>,<<"https://github.com/RujiraNetwork/rujira_ex">>}]}.
3 3 {<<"name">>,<<"rujira_ex">>}.
4 - {<<"version">>,<<"0.0.7">>}.
4 + {<<"version">>,<<"0.0.8">>}.
5 5 {<<"description">>,<<"Domain library for Rujira">>}.
6 6 {<<"elixir">>,<<"~> 1.18">>}.
7 7 {<<"files">>,
  @@ -74,7 +74,7 @@ defmodule Rujira.Events do
74 74 do: Rujira.Fin.Events.parse(event)
75 75
76 76 defp route(%Event{type: type} = event)
77 - when type in ~w(swap transfer add_liquidity withdraw pending_liquidity oracle_price bond rebond set_mimir),
77 + when type in ~w(swap transfer add_liquidity withdraw pending_liquidity oracle_price bond rebond rewards affiliate_fee set_mimir),
78 78 do: Rujira.Thorchain.Events.parse(event)
79 79
80 80 # --- Not yet implemented ---
  @@ -16,6 +16,7 @@ defmodule Rujira.Fin do
16 16 defdelegate get_pair(address), to: Pair, as: :get
17 17 defdelegate list_pairs(), to: Pair, as: :list
18 18 defdelegate get_stable_pair(denom), to: Pair, as: :find_stable
19 + defdelegate get_default_pair(denom), to: Pair, as: :find_default
19 20 defdelegate denom_for_ticker(ticker), to: Pair
20 21 defdelegate get_pair_from_denoms(base, quote_denom), to: Pair, as: :find_by_denoms
21 22 defdelegate pair_from_id(id), to: Pair, as: :from_id
  @@ -3,19 +3,22 @@ defmodule Rujira.Fin.Events.TradeRange do
3 3 A single range touched by a concentrated-liquidity trade.
4 4
5 5 The contract joins one entry per range into the trade event's `ranges`
6 - attribute with commas. Each entry is colon-separated and the fee occupies a
7 - different slot depending on the fill side:
6 + attribute with commas. Each entry is colon-separated. The leading segment is
7 + the range id, which itself embeds the price bounds as `idx:low-high`, so a
8 + full entry has the shape:
8 9
9 - * base-side fill: `idx:base:quote:deduct:add::fee` (6th slot empty)
10 - * quote-side fill: `idx:base:quote:deduct:add:fee:` (7th slot empty)
10 + * base-side fill: `idx:low-high:base:quote:deduct:add::fee` (7th slot empty)
11 + * quote-side fill: `idx:low-high:base:quote:deduct:add:fee:` (8th slot empty)
11 12
12 - All amounts are the range's internal full-precision `Decimal` values, not
13 - 8-decimal token integers.
13 + All amounts and bounds are the range's internal full-precision `Decimal`
14 + values, not 8-decimal token integers.
14 15 """
15 16
16 17 alias Rujira.Math
17 18
18 19 defstruct idx: 0,
20 + low: Decimal.new(0),
21 + high: Decimal.new(0),
19 22 side: :base,
20 23 base: Decimal.new(0),
21 24 quote: Decimal.new(0),
  @@ -25,6 +28,8 @@ defmodule Rujira.Fin.Events.TradeRange do
25 28
26 29 @type t :: %__MODULE__{
27 30 idx: non_neg_integer(),
31 + low: Decimal.t(),
32 + high: Decimal.t(),
28 33 side: :base | :quote,
29 34 base: Decimal.t(),
30 35 quote: Decimal.t(),
  @@ -55,9 +60,12 @@ defmodule Rujira.Fin.Events.TradeRange do
55 60
56 61 @spec parse(String.t()) :: {:ok, t()} | {:error, term()}
57 62 def parse(entry) when is_binary(entry) do
58 - with [idx, base, quote, deduct, add, f6, f7] <- String.split(entry, ":"),
59 - {:ok, {side, fee}} <- fee_slot(f6, f7),
63 + with [idx, bounds, base, quote, deduct, add, f7, f8] <- String.split(entry, ":"),
64 + [low, high] <- String.split(bounds, "-"),
65 + {:ok, {side, fee}} <- fee_slot(f7, f8),
60 66 {:ok, idx} <- Math.to_integer(idx),
67 + {:ok, low} <- Math.to_decimal(low),
68 + {:ok, high} <- Math.to_decimal(high),
61 69 {:ok, base} <- Math.to_decimal(base),
62 70 {:ok, quote} <- Math.to_decimal(quote),
63 71 {:ok, deduct} <- Math.to_decimal(deduct),
  @@ -66,6 +74,8 @@ defmodule Rujira.Fin.Events.TradeRange do
66 74 {:ok,
67 75 %__MODULE__{
68 76 idx: idx,
77 + low: low,
78 + high: high,
69 79 side: side,
70 80 base: base,
71 81 quote: quote,
  @@ -118,13 +118,7 @@ defmodule Rujira.Fin.Pair do
118 118 @spec find_stable(String.t()) :: {:ok, t()} | {:error, term()}
119 119 def find_stable(base_denom) do
120 120 with {:ok, pairs} <- list(),
121 - %__MODULE__{} = pair <-
122 - Enum.find(
123 - pairs,
124 - &(&1.token_base == base_denom &&
125 - (String.contains?(&1.token_quote, "usdc") ||
126 - String.contains?(&1.token_quote, "usdt")))
127 - ) do
121 + %__MODULE__{} = pair <- Enum.find(pairs, &stable_pair?(&1, base_denom)) do
128 122 {:ok, pair}
129 123 else
130 124 nil -> {:error, :not_found}
  @@ -132,6 +126,36 @@ defmodule Rujira.Fin.Pair do
132 126 end
133 127 end
134 128
129 + @doc """
130 + Finds the default pair for a base denom: prefers a stable (usdc/usdt) quote,
131 + otherwise falls back to the first pair quoting that base.
132 + """
133 + @spec find_default(String.t()) :: {:ok, t()} | {:error, term()}
134 + def find_default(base_denom) do
135 + with {:ok, pairs} <- list() do
136 + pick_default(pairs, base_denom)
137 + end
138 + end
139 +
140 + @doc false
141 + @spec pick_default([t()], String.t()) :: {:ok, t()} | {:error, :not_found}
142 + def pick_default(pairs, base_denom) do
143 + stable = Enum.find(pairs, &stable_pair?(&1, base_denom))
144 + first = Enum.find(pairs, &(&1.token_base == base_denom))
145 +
146 + case stable || first do
147 + %__MODULE__{} = pair -> {:ok, pair}
148 + nil -> {:error, :not_found}
149 + end
150 + end
151 +
152 + defp stable_pair?(%__MODULE__{token_base: base_denom, token_quote: quote}, base_denom)
153 + when is_binary(quote) do
154 + String.contains?(quote, "usdc") or String.contains?(quote, "usdt")
155 + end
156 +
157 + defp stable_pair?(_, _), do: false
158 +
135 159 @doc """
136 160 Memoized lookup of the preferred base denom for a ticker.
Loading more files…