Sort validator pools by APY descending in Staking DApp

pull/3712/head
POA 4 years ago
parent d66e4da176
commit cfaa2d7a3f
  1. 2
      .dialyzer-ignore
  2. 93
      apps/block_scout_web/lib/block_scout_web/controllers/stakes_controller.ex
  3. 5
      apps/explorer/lib/explorer/staking/contract_state.ex
  4. 56
      apps/explorer/lib/explorer/staking/stake_snapshotting.ex

@ -25,4 +25,4 @@ lib/explorer/exchange_rates/source.ex:113
lib/explorer/smart_contract/verifier.ex:89 lib/explorer/smart_contract/verifier.ex:89
lib/block_scout_web/templates/address_contract/index.html.eex:118 lib/block_scout_web/templates/address_contract/index.html.eex:118
lib/explorer/staking/stake_snapshotting.ex:15: Function do_snapshotting/6 has no local return lib/explorer/staking/stake_snapshotting.ex:15: Function do_snapshotting/6 has no local return
lib/explorer/staking/stake_snapshotting.ex:202 lib/explorer/staking/stake_snapshotting.ex:214

@ -70,10 +70,15 @@ defmodule BlockScoutWeb.StakesController do
if Map.has_key?(params, "filterMy") do if Map.has_key?(params, "filterMy") do
[paging_options: options] = paging_options(params) [paging_options: options] = paging_options(params)
last_index = # turn off paging for Validators page as we sort by APY below
params # and max number of validators is no more than 19
|> Map.get("position", "0") # (for the current POSDAO implementation)
|> String.to_integer() options =
if is_page_unlimited?(filter) do
Map.put(options, :page_size, 1_000_000)
else
options
end
pools_plus_one = pools_plus_one =
Chain.staking_pools( Chain.staking_pools(
@ -86,21 +91,7 @@ defmodule BlockScoutWeb.StakesController do
params["filterMy"] == "true" params["filterMy"] == "true"
) )
{pools, next_page} = split_list_by_page(pools_plus_one) {pools, next_page_path, last_index} = get_one_page(filter, conn, params, pools_plus_one)
next_page_path =
case next_page_params(next_page, pools, params) do
nil ->
nil
next_page_params ->
updated_page_params =
next_page_params
|> Map.delete("type")
|> Map.put("position", last_index + 1)
next_page_path(filter, conn, updated_page_params)
end
average_block_time = AverageBlockTime.average_block_time() average_block_time = AverageBlockTime.average_block_time()
@ -119,14 +110,13 @@ defmodule BlockScoutWeb.StakesController do
calc_apy_enabled = ContractState.calc_apy_enabled?() calc_apy_enabled = ContractState.calc_apy_enabled?()
snapshotted_delegator_data = snapshotted_delegator_data(filter, calc_apy_enabled) snapshotted_delegator_data = snapshotted_delegator_data(filter, calc_apy_enabled)
items = pools =
pools pools
|> Enum.with_index(last_index + 1) |> Enum.map(fn %{pool: pool} = item ->
|> Enum.map(fn {%{pool: pool, delegator: delegator}, index} ->
apy = apy =
if calc_apy_enabled and snapshotted_delegator_data != nil do if calc_apy_enabled and snapshotted_delegator_data !== nil do
calc_apy( calc_apy(
pool, item.pool,
pool_rewards, pool_rewards,
snapshotted_delegator_data, snapshotted_delegator_data,
average_block_time_seconds, average_block_time_seconds,
@ -134,11 +124,22 @@ defmodule BlockScoutWeb.StakesController do
) )
end end
pool = Map.put(pool, :apy, apy)
Map.put(item, :pool, pool)
end)
# sort pools on Validators page by descending APY if all APYs known
pools = sort_pools_by_apy(pools)
items =
pools
|> Enum.with_index(last_index + 1)
|> Enum.map(fn {%{pool: pool, delegator: delegator}, index} ->
View.render_to_string( View.render_to_string(
StakesView, StakesView,
"_rows.html", "_rows.html",
token: token, token: token,
pool: Map.put(pool, :apy, apy), pool: pool,
delegator: delegator, delegator: delegator,
index: index, index: index,
average_block_time: average_block_time, average_block_time: average_block_time,
@ -227,8 +228,50 @@ defmodule BlockScoutWeb.StakesController do
end end
end end
defp sort_pools_by_apy(pools) do
if Enum.all?(pools, fn item -> item.pool.apy !== nil end) do
Enum.sort(pools, fn item1, item2 -> item1.pool.apy.apy_raw >= item2.pool.apy.apy_raw end)
else
pools
end
end
defp address_bytes_to_string(hash), do: "0x" <> Base.encode16(hash, case: :lower) defp address_bytes_to_string(hash), do: "0x" <> Base.encode16(hash, case: :lower)
defp get_one_page(filter, conn, params, pools_plus_one) do
last_index =
params
|> Map.get("position", "0")
|> String.to_integer()
{pools, next_page} =
if is_page_unlimited?(filter) do
{pools_plus_one, []}
else
split_list_by_page(pools_plus_one)
end
next_page_path =
case next_page_params(next_page, pools, params) do
nil ->
nil
next_page_params ->
updated_page_params =
next_page_params
|> Map.delete("type")
|> Map.put("position", last_index + 1)
next_page_path(filter, conn, updated_page_params)
end
{pools, next_page_path, last_index}
end
defp is_page_unlimited?(filter) do
filter == :validator
end
defp next_page_path(:validator, conn, params) do defp next_page_path(:validator, conn, params) do
validators_path(conn, :index, params) validators_path(conn, :index, params)
end end

@ -296,7 +296,8 @@ defmodule Explorer.Staking.ContractState do
epochs_per_year = floor(31_536_000 / average_block_time / staking_epoch_duration) epochs_per_year = floor(31_536_000 / average_block_time / staking_epoch_duration)
predicted_reward = decimal_to_float(reward_ratio) * pool_reward / 100 predicted_reward = decimal_to_float(reward_ratio) * pool_reward / 100
apy = predicted_reward / decimal_to_integer(stake_amount) * epochs_per_year * 100 apy = predicted_reward / decimal_to_integer(stake_amount) * epochs_per_year * 100
%{apy: "#{floor(apy * 100) / 100}%", predicted_reward: floor(predicted_reward)} apy_raw = floor(apy * 100) / 100
%{apy: "#{apy_raw}%", predicted_reward: floor(predicted_reward), apy_raw: apy_raw}
end end
end end
@ -349,7 +350,7 @@ defmodule Explorer.Staking.ContractState do
defp start_snapshotting?(global_responses) do defp start_snapshotting?(global_responses) do
global_responses.epoch_number > get(:snapshotted_epoch_number) && global_responses.epoch_number > 0 && global_responses.epoch_number > get(:snapshotted_epoch_number) && global_responses.epoch_number > 0 &&
not get(:is_snapshotting) && (global_responses.epoch_number >= 49 || global_responses.epoch_number < 47) not get(:is_snapshotting)
end end
defp update_database( defp update_database(

@ -21,6 +21,12 @@ defmodule Explorer.Staking.StakeSnapshotting do
mining_address_to_id, mining_address_to_id,
block_number block_number
) do ) do
# temporary code (should be removed after staking epoch #48 on xDai is finished).
# this is a block number from which POSDAO on xDai chain started to use other signatures
# in the StakingAuRa contract
{:ok, net_version} = EthereumJSONRPC.fetch_net_version(Application.get_env(:explorer, :json_rpc_named_arguments))
new_signatures = (net_version == 100 and block_number > 14_994_040) or net_version != 100
# get pool ids and staking addresses for the pending validators # get pool ids and staking addresses for the pending validators
pool_ids = pool_ids =
pools_mining_addresses pools_mining_addresses
@ -51,7 +57,7 @@ defmodule Explorer.Staking.StakeSnapshotting do
Map.merge( Map.merge(
resp, resp,
ContractReader.perform_requests( ContractReader.perform_requests(
snapshotted_pool_amounts_requests(pool_id, resp.staking_address_hash, block_number), snapshotted_pool_amounts_requests(pool_id, resp.staking_address_hash, block_number, new_signatures),
contracts, contracts,
abi abi
) )
@ -66,7 +72,7 @@ defmodule Explorer.Staking.StakeSnapshotting do
}, },
ContractReader.perform_requests( ContractReader.perform_requests(
ContractReader.active_delegators_request(pool_id, block_number) ++ ContractReader.active_delegators_request(pool_id, block_number) ++
snapshotted_pool_amounts_requests(pool_id, pool_staking_address, block_number), snapshotted_pool_amounts_requests(pool_id, pool_staking_address, block_number, new_signatures),
contracts, contracts,
abi abi
) )
@ -89,7 +95,13 @@ defmodule Explorer.Staking.StakeSnapshotting do
stakers stakers
|> Enum.map(fn {pool_id, pool_staking_address, staker_address} -> |> Enum.map(fn {pool_id, pool_staking_address, staker_address} ->
ContractReader.perform_requests( ContractReader.perform_requests(
snapshotted_staker_amount_request(pool_id, pool_staking_address, staker_address, block_number), snapshotted_staker_amount_request(
pool_id,
pool_staking_address,
staker_address,
block_number,
new_signatures
),
contracts, contracts,
abi abi
) )
@ -219,18 +231,30 @@ defmodule Explorer.Staking.StakeSnapshotting do
defp address_bytes_to_string(hash), do: "0x" <> Base.encode16(hash, case: :lower) defp address_bytes_to_string(hash), do: "0x" <> Base.encode16(hash, case: :lower)
defp snapshotted_pool_amounts_requests(pool_id, pool_staking_address, block_number) do defp snapshotted_pool_amounts_requests(pool_id, pool_staking_address, block_number, new_signatures) do
stake_amount_total_signature =
if new_signatures do
# keccak256(stakeAmountTotal(uint256))
"2a8f6ecd"
else
# keccak256(stakeAmountTotal(address))
"5267e1d6"
end
[ [
# 2a8f6ecd = keccak256(stakeAmountTotal(uint256)) snapshotted_total_staked_amount: {:staking, stake_amount_total_signature, [pool_id], block_number},
snapshotted_total_staked_amount: {:staking, "2a8f6ecd", [pool_id], block_number},
snapshotted_self_staked_amount: snapshotted_self_staked_amount:
snapshotted_staker_amount_request(pool_id, pool_staking_address, pool_staking_address, block_number)[ snapshotted_staker_amount_request(
:snapshotted_stake_amount pool_id,
] pool_staking_address,
pool_staking_address,
block_number,
new_signatures
)[:snapshotted_stake_amount]
] ]
end end
defp snapshotted_staker_amount_request(pool_id, pool_staking_address, staker_address, block_number) do defp snapshotted_staker_amount_request(pool_id, pool_staking_address, staker_address, block_number, new_signatures) do
delegator_or_zero = delegator_or_zero =
if staker_address == pool_staking_address do if staker_address == pool_staking_address do
"0x0000000000000000000000000000000000000000" "0x0000000000000000000000000000000000000000"
@ -238,9 +262,17 @@ defmodule Explorer.Staking.StakeSnapshotting do
staker_address staker_address
end end
stake_amount_signature =
if new_signatures do
# keccak256(stakeAmount(uint256,address))
"3fb1a1e4"
else
# keccak256(stakeAmount(address,address))
"a697ecff"
end
[ [
# 3fb1a1e4 = keccak256(stakeAmount(uint256,address)) snapshotted_stake_amount: {:staking, stake_amount_signature, [pool_id, delegator_or_zero], block_number}
snapshotted_stake_amount: {:staking, "3fb1a1e4", [pool_id, delegator_or_zero], block_number}
] ]
end end

Loading…
Cancel
Save