Add retrieving of validatorMinRewardPercent

staking
Vadim 5 years ago committed by Victor Baranov
parent 27ec63453f
commit a3c5acd351
  1. 4
      apps/block_scout_web/lib/block_scout_web/channels/stakes_channel.ex
  2. 2
      apps/block_scout_web/lib/block_scout_web/templates/stakes/_stakes_modal_delegators_list.html.eex
  3. 2
      apps/block_scout_web/lib/block_scout_web/templates/stakes/_stakes_modal_pool_info.html.eex
  4. 2
      apps/explorer/lib/explorer/chain/import/runner/staking_pools.ex
  5. 6
      apps/explorer/lib/explorer/chain/staking_pool.ex
  6. 8
      apps/explorer/lib/explorer/staking/contract_reader.ex
  7. 80
      apps/explorer/lib/explorer/staking/contract_state.ex
  8. 48
      apps/explorer/lib/explorer/staking/stake_snapshotting.ex
  9. 19
      apps/explorer/priv/contracts_abi/posdao/BlockRewardAuRa.json
  10. 9
      apps/explorer/priv/repo/migrations/20190718175620_add_block_reward_to_pools.exs
  11. 9
      apps/explorer/priv/repo/migrations/20190718175620_add_validator_reward_percent_to_pools.exs

@ -54,6 +54,7 @@ defmodule BlockScoutWeb.StakesChannel do
def handle_in("render_delegators_list", %{"address" => pool_staking_address}, socket) do
pool = Chain.staking_pool(pool_staking_address)
token = ContractState.get(:token)
validator_min_reward_percent = ContractState.get(:validator_min_reward_percent)
show_snapshotted_data =
pool.is_validator && ContractState.get(:validator_set_apply_block) > 0 && ContractState.get(:is_snapshotted)
@ -78,7 +79,8 @@ defmodule BlockScoutWeb.StakesChannel do
conn: socket,
stakers: stakers,
token: token,
show_snapshotted_data: show_snapshotted_data
show_snapshotted_data: show_snapshotted_data,
validator_min_reward_percent: validator_min_reward_percent
)
{:reply, {:ok, %{html: html}}, socket}

@ -50,7 +50,7 @@
render BlockScoutWeb.StakesView,
"_stakes_th.html",
title: reward_col_title,
tooltip: gettext("Reward distribution is based on stake amount. Validator receives a minimum of 30%.")
tooltip: gettext("Reward distribution is based on stake amount. Validator receives a minimum of %{min}%.", min: @validator_min_reward_percent)
%>
</div>
</div>

@ -47,7 +47,7 @@
render BlockScoutWeb.StakesView,
"_stakes_validator_info_item.html",
title: gettext("Share of Pool’s Reward"),
value: "#{@validator.block_reward_ratio}%"
value: "#{@validator.validator_reward_percent}%"
%>
<%=
render BlockScoutWeb.StakesView,

@ -130,7 +130,7 @@ defmodule Explorer.Chain.Import.Runner.StakingPools do
is_unremovable: fragment("EXCLUDED.is_unremovable"),
are_delegators_banned: fragment("EXCLUDED.are_delegators_banned"),
likelihood: fragment("EXCLUDED.likelihood"),
block_reward_ratio: fragment("EXCLUDED.block_reward_ratio"),
validator_reward_percent: fragment("EXCLUDED.validator_reward_percent"),
stakes_ratio: fragment("EXCLUDED.stakes_ratio"),
validator_reward_ratio: fragment("EXCLUDED.validator_reward_ratio"),
self_staked_amount: fragment("EXCLUDED.self_staked_amount"),

@ -24,7 +24,7 @@ defmodule Explorer.Chain.StakingPool do
is_unremovable: boolean,
are_delegators_banned: boolean,
likelihood: Decimal.t(),
block_reward_ratio: Decimal.t(),
validator_reward_percent: Decimal.t(),
stakes_ratio: Decimal.t(),
validator_reward_ratio: Decimal.t(),
snapshotted_validator_reward_ratio: Decimal.t(),
@ -41,7 +41,7 @@ defmodule Explorer.Chain.StakingPool do
@attrs ~w(
is_active delegators_count total_staked_amount self_staked_amount snapshotted_total_staked_amount snapshotted_self_staked_amount is_validator
was_validator_count is_banned are_delegators_banned ban_reason was_banned_count banned_until banned_delegators_until likelihood
stakes_ratio validator_reward_ratio snapshotted_validator_reward_ratio staking_address_hash mining_address_hash block_reward_ratio
stakes_ratio validator_reward_ratio snapshotted_validator_reward_ratio staking_address_hash mining_address_hash validator_reward_percent
is_unremovable
)a
@req_attrs ~w(
@ -60,7 +60,7 @@ defmodule Explorer.Chain.StakingPool do
field(:is_unremovable, :boolean, default: false)
field(:are_delegators_banned, :boolean, default: false)
field(:likelihood, :decimal)
field(:block_reward_ratio, :decimal)
field(:validator_reward_percent, :decimal)
field(:stakes_ratio, :decimal)
field(:validator_reward_ratio, :decimal)
field(:snapshotted_validator_reward_ratio, :decimal)

@ -28,7 +28,7 @@ defmodule Explorer.Staking.ContractReader do
def pool_staking_requests(staking_address) do
[
active_delegators: {:staking, "poolDelegators", [staking_address]},
block_reward: {:block_reward, "validatorRewardPercent", [staking_address]},
validator_reward_percent: {:block_reward, "validatorRewardPercent", [staking_address]},
inactive_delegators: {:staking, "poolDelegatorsInactive", [staking_address]},
is_active: {:staking, "isPoolActive", [staking_address]},
mining_address_hash: {:validator_set, "miningByStakingAddress", [staking_address]},
@ -65,6 +65,12 @@ defmodule Explorer.Staking.ContractReader do
]
end
def validator_min_reward_percent_request(epoch_number) do
[
value: {:block_reward, "validatorMinRewardPercent", [epoch_number]}
]
end
# args = [staking_epoch, validator_staked, total_staked, pool_reward \\ 10_00000]
def validator_reward_requests(args) do
[

@ -28,6 +28,7 @@ defmodule Explorer.Staking.ContractState do
:validator_set_contract,
:block_reward_contract,
:validator_set_apply_block,
:validator_min_reward_percent,
:is_snapshotted
]
@ -123,6 +124,9 @@ defmodule Explorer.Staking.ContractState do
# read general info from the contracts (including pool list and validator list)
global_responses = ContractReader.perform_requests(ContractReader.global_requests(), contracts, abi)
token = get_token(global_responses.token_contract_address)
validator_min_reward_percent = ContractReader.perform_requests(
ContractReader.validator_min_reward_percent_request(global_responses.epoch_number), contracts, abi
).value
start_snapshotting = (global_responses.epoch_start_block == block_number + 1)
is_validator = Enum.into(global_responses.validators, %{}, &{hash_to_string(&1), true})
@ -143,6 +147,7 @@ defmodule Explorer.Staking.ContractState do
])
|> Map.to_list()
|> Enum.concat(token: token)
|> Enum.concat(validator_min_reward_percent: validator_min_reward_percent)
:ets.insert(@table_name, settings)
@ -199,75 +204,79 @@ defmodule Explorer.Staking.ContractState do
# get amounts for each of the stakers
staker_responses =
stakers
|> Enum.map(fn {pool_staking_address, staker_address, _} ->
|> Enum.map(fn {pool_staking_address, staker_address, _is_active} ->
ContractReader.staker_requests(pool_staking_address, staker_address)
end)
|> ContractReader.perform_grouped_requests(stakers, contracts, abi)
# calculate total amount staked into all active pools
staked_total = Enum.sum(for {_, pool} <- pool_staking_responses, pool.is_active, do: pool.total_staked_amount)
[likelihood_values, total_likelihood] = global_responses.pools_likelihood
likelihood =
global_responses.pools_to_be_elected # array of pool addresses (staking addresses)
|> Enum.zip(likelihood_values)
|> Enum.into(%{})
# to keep sort order
pool_staking_keys = Enum.map(pool_staking_responses, fn {key, _} -> key end)
candidate_reward_responses =
pool_staking_responses
|> Enum.map(fn {_address, response} ->
|> Enum.map(fn {_pool_staking_address, resp} ->
ContractReader.validator_reward_requests([
global_responses.epoch_number,
response.self_staked_amount,
response.total_staked_amount,
resp.self_staked_amount,
resp.total_staked_amount,
1000_000
])
end)
|> ContractReader.perform_grouped_requests(pool_staking_keys, contracts, abi)
# to keep sort order
delegator_keys = Enum.map(staker_responses, fn {key, _} -> key end)
delegator_reward_responses =
staker_responses
|> Enum.map(fn {{pool_address, _, _}, response} ->
staking_response = pool_staking_responses[pool_address]
|> Enum.map(fn {{pool_staking_address, _staker_address, _is_active}, resp} ->
staking_resp = pool_staking_responses[pool_staking_address]
ContractReader.delegator_reward_requests([
global_responses.epoch_number,
response.stake_amount,
staking_response.self_staked_amount,
staking_response.total_staked_amount,
resp.stake_amount,
staking_resp.self_staked_amount,
staking_resp.total_staked_amount,
1000_000
])
end)
|> ContractReader.perform_grouped_requests(delegator_keys, contracts, abi)
# calculate total amount staked into all active pools
staked_total = Enum.sum(for {_, pool} <- pool_staking_responses, pool.is_active, do: pool.total_staked_amount)
# calculate likelihood of becoming a validator on the next epoch
[likelihood_values, total_likelihood] = global_responses.pools_likelihood
likelihood =
global_responses.pools_to_be_elected # array of pool addresses (staking addresses)
|> Enum.zip(likelihood_values)
|> Enum.into(%{})
# form entries for writing to the `staking_pools` table in DB
pool_entries =
Enum.map(pools, fn staking_address ->
staking_response = pool_staking_responses[staking_address]
mining_response = pool_mining_responses[staking_address]
candidate_reward_response = candidate_reward_responses[staking_address]
Enum.map(pools, fn pool_staking_address ->
staking_resp = pool_staking_responses[pool_staking_address]
mining_resp = pool_mining_responses[pool_staking_address]
candidate_reward_resp = candidate_reward_responses[pool_staking_address]
%{
staking_address_hash: staking_address,
delegators_count: length(staking_response.active_delegators),
staking_address_hash: pool_staking_address,
delegators_count: length(staking_resp.active_delegators),
stakes_ratio:
if staking_response.is_active do
ratio(staking_response.total_staked_amount, staked_total)
if staking_resp.is_active do
ratio(staking_resp.total_staked_amount, staked_total)
end,
validator_reward_ratio: Float.floor(candidate_reward_response.validator_share / 10_000, 2),
likelihood: ratio(likelihood[staking_address] || 0, total_likelihood),
block_reward_ratio: staking_response.block_reward / 10_000,
validator_reward_ratio: Float.floor(candidate_reward_resp.validator_share / 10_000, 2),
likelihood: ratio(likelihood[pool_staking_address] || 0, total_likelihood),
validator_reward_percent: staking_resp.validator_reward_percent / 10_000,
is_deleted: false,
is_validator: is_validator[staking_response.mining_address_hash] || false,
is_unremovable: hash_to_string(staking_address) == unremovable_validator,
ban_reason: binary_to_string(mining_response.ban_reason)
is_validator: is_validator[staking_resp.mining_address_hash] || false,
is_unremovable: hash_to_string(pool_staking_address) == unremovable_validator,
ban_reason: binary_to_string(mining_resp.ban_reason)
}
|> Map.merge(
Map.take(staking_response, [
Map.take(staking_resp, [
:is_active,
:mining_address_hash,
:self_staked_amount,
@ -275,7 +284,7 @@ defmodule Explorer.Staking.ContractState do
])
)
|> Map.merge(
Map.take(mining_response, [
Map.take(mining_resp, [
:are_delegators_banned,
:banned_delegators_until,
:banned_until,
@ -286,6 +295,7 @@ defmodule Explorer.Staking.ContractState do
)
end)
# form entries for writing to the `staking_pools_delegators` table in DB
delegator_entries =
Enum.map(staker_responses, fn {{pool_address, delegator_address, is_active}, response} ->
delegator_reward_response = delegator_reward_responses[{pool_address, delegator_address, is_active}]

@ -97,9 +97,12 @@ defmodule Explorer.Staking.StakeSnapshotting do
|> Enum.zip(stakers)
|> Map.new(fn {key, val} -> {val, key} end)
# to keep sort order
pool_staking_keys = Enum.map(pool_staking_responses, fn {key, _} -> key end)
validator_reward_responses =
pool_staking_responses
|> Enum.map(fn {_address, resp} ->
|> Enum.map(fn {_pool_staking_address, resp} ->
ContractReader.validator_reward_requests([
epoch_number,
resp.snapshotted_self_staked_amount,
@ -107,36 +110,39 @@ defmodule Explorer.Staking.StakeSnapshotting do
1000_000
])
end)
|> ContractReader.perform_grouped_requests(pool_staking_addresses, contracts, abi)
|> ContractReader.perform_grouped_requests(pool_staking_keys, contracts, abi)
# to keep sort order
delegator_keys = Enum.map(staker_responses, fn {key, _} -> key end)
delegator_reward_responses =
staker_responses
|> Enum.map(fn {{pool_address, _delegator_address}, response} ->
staking_response = pool_staking_responses[pool_address]
|> Enum.map(fn {{pool_staking_address, _staker_address}, resp} ->
staking_resp = pool_staking_responses[pool_staking_address]
ContractReader.delegator_reward_requests([
epoch_number,
response.snapshotted_stake_amount,
staking_response.snapshotted_self_staked_amount,
staking_response.snapshotted_total_staked_amount,
resp.snapshotted_stake_amount,
staking_resp.snapshotted_self_staked_amount,
staking_resp.snapshotted_total_staked_amount,
1000_000
])
end)
|> ContractReader.perform_grouped_requests(stakers, contracts, abi)
|> ContractReader.perform_grouped_requests(delegator_keys, contracts, abi)
pool_entries =
Enum.map(pool_staking_addresses, fn staking_address ->
staking_response = pool_staking_responses[staking_address]
mining_response = pool_mining_responses[staking_address]
validator_reward_response = validator_reward_responses[staking_address]
Enum.map(pool_staking_addresses, fn pool_staking_address ->
staking_resp = pool_staking_responses[pool_staking_address]
mining_resp = pool_mining_responses[pool_staking_address]
validator_reward_resp = validator_reward_responses[pool_staking_address]
%{
staking_address_hash: staking_address,
delegators_count: length(staking_response.active_delegators),
snapshotted_validator_reward_ratio: Float.floor(validator_reward_response.validator_share / 10_000, 2)
staking_address_hash: pool_staking_address,
delegators_count: length(staking_resp.active_delegators),
snapshotted_validator_reward_ratio: Float.floor(validator_reward_resp.validator_share / 10_000, 2)
}
|> Map.merge(
Map.take(staking_response, [
Map.take(staking_resp, [
:mining_address_hash,
:self_staked_amount,
:snapshotted_self_staked_amount,
@ -145,7 +151,7 @@ defmodule Explorer.Staking.StakeSnapshotting do
])
)
|> Map.merge(
Map.take(mining_response, [
Map.take(mining_resp, [
:banned_until,
:was_banned_count,
:was_validator_count
@ -154,13 +160,13 @@ defmodule Explorer.Staking.StakeSnapshotting do
end)
delegator_entries =
Enum.map(staker_responses, fn {{pool_staking_address, staker_address}, response} ->
delegator_reward_response = delegator_reward_responses[{pool_staking_address, staker_address}]
Enum.map(staker_responses, fn {{pool_staking_address, staker_address}, resp} ->
delegator_reward_resp = delegator_reward_responses[{pool_staking_address, staker_address}]
Map.merge(response, %{
Map.merge(resp, %{
address_hash: staker_address,
staking_address_hash: pool_staking_address,
snapshotted_reward_ratio: Float.floor(delegator_reward_response.delegator_share / 10_000, 2)
snapshotted_reward_ratio: Float.floor(delegator_reward_resp.delegator_share / 10_000, 2)
})
end)

@ -181,6 +181,25 @@
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "",
"type": "uint256"
}
],
"name": "validatorMinRewardPercent",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],

@ -1,9 +0,0 @@
defmodule Explorer.Repo.Migrations.AddBlockRewardToPools do
use Ecto.Migration
def change do
alter table(:staking_pools) do
add(:block_reward_ratio, :decimal, precision: 5, scale: 2)
end
end
end

@ -0,0 +1,9 @@
defmodule Explorer.Repo.Migrations.AddValidatorRewardPercentToPools do
use Ecto.Migration
def change do
alter table(:staking_pools) do
add(:validator_reward_percent, :decimal, precision: 5, scale: 2)
end
end
end
Loading…
Cancel
Save