forked from blockscout/blockscout
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7e13e38
commit 4a63b97
Showing
6 changed files
with
271 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |