parent
7e13e38f3a
commit
4a63b978fd
@ -0,0 +1,103 @@ |
|||||||
|
defmodule Explorer.Chain.Supply.RSK do |
||||||
|
@moduledoc """ |
||||||
|
Defines the supply API for calculating supply for coins from RSK. |
||||||
|
""" |
||||||
|
|
||||||
|
use Explorer.Chain.Supply |
||||||
|
|
||||||
|
import Ecto.Query, only: [from: 2] |
||||||
|
|
||||||
|
alias Explorer.Chain.Address.CoinBalance |
||||||
|
alias Explorer.Chain.{Block, Wei} |
||||||
|
alias Explorer.ExchangeRates.Token |
||||||
|
alias Explorer.{Market, Repo} |
||||||
|
|
||||||
|
def market_cap(exchange_rate) do |
||||||
|
circulating() * exchange_rate.usd_value |
||||||
|
end |
||||||
|
|
||||||
|
@doc "Equivalent to getting the circulating value " |
||||||
|
def supply_for_days(days) do |
||||||
|
now = Timex.now() |
||||||
|
|
||||||
|
balances_query = |
||||||
|
from(balance in CoinBalance, |
||||||
|
join: block in Block, |
||||||
|
on: block.number == balance.block_number, |
||||||
|
where: block.consensus == true, |
||||||
|
where: balance.address_hash == ^"0x0000000000000000000000000000000001000006", |
||||||
|
where: block.timestamp > ^Timex.shift(now, days: -days), |
||||||
|
distinct: fragment("date_trunc('day', ?)", block.timestamp), |
||||||
|
select: {block.timestamp, balance.value} |
||||||
|
) |
||||||
|
|
||||||
|
balance_before_query = |
||||||
|
from(balance in CoinBalance, |
||||||
|
join: block in Block, |
||||||
|
on: block.number == balance.block_number, |
||||||
|
where: block.consensus == true, |
||||||
|
where: balance.address_hash == ^"0x0000000000000000000000000000000001000006", |
||||||
|
where: block.timestamp <= ^Timex.shift(Timex.now(), days: -days), |
||||||
|
order_by: [desc: block.timestamp], |
||||||
|
limit: 1, |
||||||
|
select: balance.value |
||||||
|
) |
||||||
|
|
||||||
|
by_day = |
||||||
|
balances_query |
||||||
|
|> Repo.all() |
||||||
|
|> Enum.into(%{}, fn {timestamp, value} -> |
||||||
|
{Timex.to_date(timestamp), value} |
||||||
|
end) |
||||||
|
|
||||||
|
starting = Repo.one(balance_before_query) || wei!(0) |
||||||
|
|
||||||
|
result = |
||||||
|
-days..0 |
||||||
|
|> Enum.reduce({%{}, starting.value}, fn i, {days, last} -> |
||||||
|
date = |
||||||
|
now |
||||||
|
|> Timex.shift(days: i) |
||||||
|
|> Timex.to_date() |
||||||
|
|
||||||
|
case Map.get(by_day, date) do |
||||||
|
nil -> |
||||||
|
{Map.put(days, date, last), last} |
||||||
|
|
||||||
|
value -> |
||||||
|
{Map.put(days, date, value.value), value.value} |
||||||
|
end |
||||||
|
end) |
||||||
|
|> elem(0) |
||||||
|
|
||||||
|
{:ok, result} |
||||||
|
end |
||||||
|
|
||||||
|
def circulating do |
||||||
|
query = |
||||||
|
from(balance in CoinBalance, |
||||||
|
join: block in Block, |
||||||
|
on: block.number == balance.block_number, |
||||||
|
where: block.consensus == true, |
||||||
|
where: balance.address_hash == ^"0x0000000000000000000000000000000001000006", |
||||||
|
order_by: [desc: block.timestamp], |
||||||
|
limit: 1, |
||||||
|
select: balance.value |
||||||
|
) |
||||||
|
|
||||||
|
Repo.one(query) || wei!(0) |
||||||
|
end |
||||||
|
|
||||||
|
defp wei!(value) do |
||||||
|
{:ok, wei} = Wei.cast(value) |
||||||
|
wei |
||||||
|
end |
||||||
|
|
||||||
|
def total do |
||||||
|
21_000_000 |
||||||
|
end |
||||||
|
|
||||||
|
def exchange_rate do |
||||||
|
Market.get_exchange_rate(Explorer.coin()) || Token.null() |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,139 @@ |
|||||||
|
defmodule Explorer.Chain.Supply.RSKTest do |
||||||
|
use Explorer.DataCase |
||||||
|
|
||||||
|
alias Explorer.Chain.Supply.RSK |
||||||
|
alias Explorer.Chain.Wei |
||||||
|
|
||||||
|
@coin_address "0x0000000000000000000000000000000001000006" |
||||||
|
|
||||||
|
defp wei!(value) do |
||||||
|
{:ok, wei} = Wei.cast(value) |
||||||
|
wei |
||||||
|
end |
||||||
|
|
||||||
|
test "total is 21_000_000" do |
||||||
|
assert RSK.total() == 21_000_000 |
||||||
|
end |
||||||
|
|
||||||
|
describe "circulating/0" do |
||||||
|
test "with no balance" do |
||||||
|
assert RSK.circulating() == wei!(0) |
||||||
|
end |
||||||
|
|
||||||
|
test "with a balance" do |
||||||
|
address = insert(:address, hash: @coin_address) |
||||||
|
insert(:block, number: 0) |
||||||
|
|
||||||
|
insert(:fetched_balance, value: 10, address_hash: address.hash, block_number: 0) |
||||||
|
|
||||||
|
assert RSK.circulating() == wei!(10) |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
defp date(now, shift \\ []) do |
||||||
|
now |
||||||
|
|> Timex.shift(shift) |
||||||
|
|> Timex.to_date() |
||||||
|
end |
||||||
|
|
||||||
|
defp dec(number) do |
||||||
|
Decimal.new(number) |
||||||
|
end |
||||||
|
|
||||||
|
describe "supply_for_days/1" do |
||||||
|
test "when there is no balance" do |
||||||
|
now = Timex.now() |
||||||
|
|
||||||
|
assert RSK.supply_for_days(2) == |
||||||
|
{:ok, |
||||||
|
%{ |
||||||
|
date(now, days: -2) => dec(0), |
||||||
|
date(now, days: -1) => dec(0), |
||||||
|
date(now) => dec(0) |
||||||
|
}} |
||||||
|
end |
||||||
|
|
||||||
|
test "when there is a single balance before the days, that balance is used" do |
||||||
|
address = insert(:address, hash: @coin_address) |
||||||
|
now = Timex.now() |
||||||
|
|
||||||
|
insert(:block, number: 0, timestamp: Timex.shift(now, days: -10)) |
||||||
|
|
||||||
|
insert(:fetched_balance, value: 10, address_hash: address.hash, block_number: 0) |
||||||
|
|
||||||
|
assert RSK.supply_for_days(2) == |
||||||
|
{:ok, |
||||||
|
%{ |
||||||
|
date(now, days: -2) => dec(10), |
||||||
|
date(now, days: -1) => dec(10), |
||||||
|
date(now) => dec(10) |
||||||
|
}} |
||||||
|
end |
||||||
|
|
||||||
|
test "when there is a balance for one of the days, days after it use that balance" do |
||||||
|
address = insert(:address, hash: @coin_address) |
||||||
|
now = Timex.now() |
||||||
|
|
||||||
|
insert(:block, number: 0, timestamp: Timex.shift(now, days: -10)) |
||||||
|
insert(:block, number: 1, timestamp: Timex.shift(now, days: -1)) |
||||||
|
|
||||||
|
insert(:fetched_balance, value: 10, address_hash: address.hash, block_number: 0) |
||||||
|
|
||||||
|
insert(:fetched_balance, value: 20, address_hash: address.hash, block_number: 1) |
||||||
|
|
||||||
|
assert RSK.supply_for_days(2) == |
||||||
|
{:ok, |
||||||
|
%{ |
||||||
|
date(now, days: -2) => dec(10), |
||||||
|
date(now, days: -1) => dec(20), |
||||||
|
date(now) => dec(20) |
||||||
|
}} |
||||||
|
end |
||||||
|
|
||||||
|
test "when there is a balance for the first day, that balance is used" do |
||||||
|
address = insert(:address, hash: @coin_address) |
||||||
|
now = Timex.now() |
||||||
|
|
||||||
|
insert(:block, number: 0, timestamp: Timex.shift(now, days: -10)) |
||||||
|
insert(:block, number: 1, timestamp: Timex.shift(now, days: -2)) |
||||||
|
insert(:block, number: 2, timestamp: Timex.shift(now, days: -1)) |
||||||
|
|
||||||
|
insert(:fetched_balance, value: 5, address_hash: address.hash, block_number: 0) |
||||||
|
|
||||||
|
insert(:fetched_balance, value: 10, address_hash: address.hash, block_number: 1) |
||||||
|
|
||||||
|
insert(:fetched_balance, value: 20, address_hash: address.hash, block_number: 2) |
||||||
|
|
||||||
|
assert RSK.supply_for_days(2) == |
||||||
|
{:ok, |
||||||
|
%{ |
||||||
|
date(now, days: -2) => dec(10), |
||||||
|
date(now, days: -1) => dec(20), |
||||||
|
date(now) => dec(20) |
||||||
|
}} |
||||||
|
end |
||||||
|
|
||||||
|
test "when there is a balance for all days, they are each used correctly" do |
||||||
|
address = insert(:address, hash: @coin_address) |
||||||
|
now = Timex.now() |
||||||
|
|
||||||
|
insert(:block, number: 0, timestamp: Timex.shift(now, days: -10)) |
||||||
|
insert(:block, number: 1, timestamp: Timex.shift(now, days: -2)) |
||||||
|
insert(:block, number: 2, timestamp: Timex.shift(now, days: -1)) |
||||||
|
insert(:block, number: 3, timestamp: now) |
||||||
|
|
||||||
|
insert(:fetched_balance, value: 5, address_hash: address.hash, block_number: 0) |
||||||
|
insert(:fetched_balance, value: 10, address_hash: address.hash, block_number: 1) |
||||||
|
insert(:fetched_balance, value: 20, address_hash: address.hash, block_number: 2) |
||||||
|
insert(:fetched_balance, value: 30, address_hash: address.hash, block_number: 3) |
||||||
|
|
||||||
|
assert RSK.supply_for_days(2) == |
||||||
|
{:ok, |
||||||
|
%{ |
||||||
|
date(now, days: -2) => dec(10), |
||||||
|
date(now, days: -1) => dec(20), |
||||||
|
date(now) => dec(30) |
||||||
|
}} |
||||||
|
end |
||||||
|
end |
||||||
|
end |
Loading…
Reference in new issue