diff --git a/apps/explorer/lib/explorer/chain/import/runner/staking_pools.ex b/apps/explorer/lib/explorer/chain/import/runner/staking_pools.ex index 35ccea981a..7eecebea3d 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/staking_pools.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/staking_pools.ex @@ -132,6 +132,7 @@ defmodule Explorer.Chain.Import.Runner.StakingPools do likelihood: fragment("EXCLUDED.likelihood"), block_reward_ratio: fragment("EXCLUDED.block_reward_ratio"), staked_ratio: fragment("EXCLUDED.staked_ratio"), + snapshotted_staked_ratio: pool.snapshotted_staked_ratio, self_staked_amount: fragment("EXCLUDED.self_staked_amount"), staked_amount: fragment("EXCLUDED.staked_amount"), snapshotted_self_staked_amount: pool.snapshotted_self_staked_amount, diff --git a/apps/explorer/lib/explorer/chain/import/runner/staking_pools_delegators.ex b/apps/explorer/lib/explorer/chain/import/runner/staking_pools_delegators.ex index 53cfeef4e3..f1fa186643 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/staking_pools_delegators.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/staking_pools_delegators.ex @@ -112,6 +112,7 @@ defmodule Explorer.Chain.Import.Runner.StakingPoolsDelegators do max_ordered_withdraw_allowed: fragment("EXCLUDED.max_ordered_withdraw_allowed"), ordered_withdraw_epoch: fragment("EXCLUDED.ordered_withdraw_epoch"), reward_ratio: fragment("EXCLUDED.reward_ratio"), + snapshotted_reward_ratio: delegator.snapshotted_reward_ratio, inserted_at: fragment("LEAST(?, EXCLUDED.inserted_at)", delegator.inserted_at), updated_at: fragment("GREATEST(?, EXCLUDED.updated_at)", delegator.updated_at), is_active: fragment("EXCLUDED.is_active"), diff --git a/apps/explorer/lib/explorer/chain/staking_pool.ex b/apps/explorer/lib/explorer/chain/staking_pool.ex index 7565a94427..7414709cc4 100644 --- a/apps/explorer/lib/explorer/chain/staking_pool.ex +++ b/apps/explorer/lib/explorer/chain/staking_pool.ex @@ -26,6 +26,7 @@ defmodule Explorer.Chain.StakingPool do likelihood: Decimal.t(), block_reward_ratio: Decimal.t(), staked_ratio: Decimal.t(), + snapshotted_staked_ratio: Decimal.t(), self_staked_amount: Decimal.t(), staked_amount: Decimal.t(), snapshotted_self_staked_amount: Decimal.t(), @@ -39,7 +40,7 @@ defmodule Explorer.Chain.StakingPool do @attrs ~w( is_active delegators_count staked_amount self_staked_amount snapshotted_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 - staked_ratio staking_address_hash mining_address_hash block_reward_ratio + staked_ratio snapshotted_staked_ratio staking_address_hash mining_address_hash block_reward_ratio is_unremovable )a @req_attrs ~w( @@ -60,6 +61,7 @@ defmodule Explorer.Chain.StakingPool do field(:likelihood, :decimal) field(:block_reward_ratio, :decimal) field(:staked_ratio, :decimal) + field(:snapshotted_staked_ratio, :decimal) field(:self_staked_amount, :decimal) field(:staked_amount, :decimal) field(:snapshotted_self_staked_amount, :decimal) diff --git a/apps/explorer/lib/explorer/chain/staking_pools_delegator.ex b/apps/explorer/lib/explorer/chain/staking_pools_delegator.ex index 5f91fbfbe1..ae9c273bf7 100644 --- a/apps/explorer/lib/explorer/chain/staking_pools_delegator.ex +++ b/apps/explorer/lib/explorer/chain/staking_pools_delegator.ex @@ -22,6 +22,7 @@ defmodule Explorer.Chain.StakingPoolsDelegator do stake_amount: Decimal.t(), snapshotted_stake_amount: Decimal.t(), reward_ratio: Decimal.t(), + snapshotted_reward_ratio: Decimal.t(), is_active: boolean(), is_deleted: boolean() } @@ -29,13 +30,12 @@ defmodule Explorer.Chain.StakingPoolsDelegator do @attrs ~w( pool_address_hash delegator_address_hash max_ordered_withdraw_allowed max_withdraw_allowed ordered_withdraw stake_amount snapshotted_stake_amount ordered_withdraw_epoch - reward_ratio is_active is_deleted + reward_ratio snapshotted_reward_ratio is_active is_deleted )a @req_attrs ~w( pool_address_hash delegator_address_hash max_ordered_withdraw_allowed max_withdraw_allowed ordered_withdraw stake_amount ordered_withdraw_epoch - )a schema "staking_pools_delegators" do @@ -46,6 +46,7 @@ defmodule Explorer.Chain.StakingPoolsDelegator do field(:stake_amount, :decimal) field(:snapshotted_stake_amount, :decimal) field(:reward_ratio, :decimal) + field(:snapshotted_reward_ratio, :decimal) field(:is_active, :boolean, default: true) field(:is_deleted, :boolean, default: false) diff --git a/apps/explorer/lib/explorer/staking/contract_reader.ex b/apps/explorer/lib/explorer/staking/contract_reader.ex index 16f5fe5679..1feff6c283 100644 --- a/apps/explorer/lib/explorer/staking/contract_reader.ex +++ b/apps/explorer/lib/explorer/staking/contract_reader.ex @@ -59,6 +59,20 @@ defmodule Explorer.Staking.ContractReader do ] end + # args = [staking_epoch, validator_staked, total_staked, pool_reward \\ 10_00000] + def pool_reward_requests(args) do + [ + validator_share: {:block_reward, "validatorShare", args}, + ] + end + + # args = [staking_epoch, delegator_staked, validator_staked, total_staked, pool_reward \\ 10_00000] + def delegator_reward_requests(args) do + [ + delegator_share: {:block_reward, "delegatorShare", args}, + ] + end + def perform_requests(requests, contracts, abi) do requests |> generate_requests(contracts) diff --git a/apps/explorer/lib/explorer/staking/contract_state.ex b/apps/explorer/lib/explorer/staking/contract_state.ex index c8fea7c764..5116a5bef5 100644 --- a/apps/explorer/lib/explorer/staking/contract_state.ex +++ b/apps/explorer/lib/explorer/staking/contract_state.ex @@ -164,7 +164,6 @@ defmodule Explorer.Staking.ContractState do end) |> ContractReader.perform_grouped_requests(delegators, contracts, abi) - staked_total = Enum.sum(for {_, pool} <- pool_staking_responses, pool.is_active, do: pool.staked_amount) [likelihood_values, total_likelihood] = global_responses.pools_likelihood likelihood = @@ -172,18 +171,42 @@ defmodule Explorer.Staking.ContractState do |> Enum.zip(likelihood_values) |> Enum.into(%{}) + pool_reward_responses = + pool_staking_responses + |> Enum.map(fn {_address, response} -> + ContractReader.pool_reward_requests([ + global_responses.epoch_number, + response.self_staked_amount, + response.staked_amount, + 1000_000 + ]) + end) + |> ContractReader.perform_grouped_requests(pools, contracts, abi) + + delegator_reward_responses = + delegator_responses + |> Enum.map(fn {{pool_address, _, _}, response} -> + staking_response = pool_staking_responses[pool_address] + ContractReader.delegator_reward_requests([ + global_responses.epoch_number, + response.stake_amount, + staking_response.self_staked_amount, + staking_response.staked_amount, + 1000_000 + ]) + end) + |> ContractReader.perform_grouped_requests(delegators, contracts, abi) + pool_entries = Enum.map(pools, fn staking_address -> staking_response = pool_staking_responses[staking_address] mining_response = pool_mining_responses[staking_address] + pool_reward_response = pool_reward_responses[staking_address] %{ staking_address_hash: staking_address, delegators_count: length(staking_response.active_delegators), - staked_ratio: - if staking_response.is_active do - ratio(staking_response.staked_amount, staked_total) - end, + staked_ratio: pool_reward_response.validator_share / 10_000, likelihood: ratio(likelihood[staking_address] || 0, total_likelihood), block_reward_ratio: staking_response.block_reward / 10_000, is_deleted: false, @@ -213,10 +236,12 @@ defmodule Explorer.Staking.ContractState do delegator_entries = Enum.map(delegator_responses, fn {{pool_address, delegator_address, is_active}, response} -> + delegator_reward_response = delegator_reward_responses[{pool_address, delegator_address, is_active}] Map.merge(response, %{ delegator_address_hash: delegator_address, pool_address_hash: pool_address, - is_active: is_active + is_active: is_active, + reward_ratio: delegator_reward_response.delegator_share / 10_000 }) end) diff --git a/apps/explorer/lib/explorer/staking/stake_snapshotting.ex b/apps/explorer/lib/explorer/staking/stake_snapshotting.ex index 3b79a2e698..de2a32c38c 100644 --- a/apps/explorer/lib/explorer/staking/stake_snapshotting.ex +++ b/apps/explorer/lib/explorer/staking/stake_snapshotting.ex @@ -9,7 +9,10 @@ defmodule Explorer.Staking.StakeSnapshotting do use GenServer + import Ecto.Query, only: [from: 2] + alias Explorer.Chain + alias Explorer.Chain.{StakingPool, StakingPoolsDelegator} alias Explorer.SmartContract.Reader alias Explorer.Staking.ContractReader @@ -65,6 +68,7 @@ defmodule Explorer.Staking.StakeSnapshotting do "validatorsToBeFinalized" => [] }) + global_responses = ContractReader.perform_requests(ContractReader.global_requests(), contracts, abi) pool_mining_addresses = pending_validators_mining_addresses ++ be_finalized_validators_mining_addresses pool_staking_addresses = @@ -98,14 +102,40 @@ defmodule Explorer.Staking.StakeSnapshotting do end) |> ContractReader.perform_grouped_requests(delegators, contracts, abi) + pool_reward_responses = + pool_staking_responses + |> Enum.map(fn {_address, response} -> + ContractReader.pool_reward_requests([ + global_responses.epoch_number, + response.snapshotted_self_staked_amount, + response.snapshotted_staked_amount, + 1000_000]) + end) + |> ContractReader.perform_grouped_requests(pool_staking_addresses, contracts, abi) + + delegator_reward_responses = + delegator_responses + |> Enum.map(fn {{pool_address, _delegator_address, _}, response} -> + staking_response = pool_staking_responses[pool_address] + ContractReader.delegator_reward_requests([ + global_responses.epoch_number, + response.stake_amount, + staking_response.snapshotted_self_staked_amount, + staking_response.snapshotted_staked_amount, + 1000_000]) + end) + |> ContractReader.perform_grouped_requests(delegators, 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] + pool_reward_response = pool_reward_responses[staking_address] %{ staking_address_hash: staking_address, - delegators_count: length(staking_response.active_delegators) + delegators_count: length(staking_response.active_delegators), + snapshotted_staked_ratio: pool_reward_response.validator_share / 10_000, } |> Map.merge( Map.take(staking_response, [ @@ -127,19 +157,20 @@ defmodule Explorer.Staking.StakeSnapshotting do delegator_entries = Enum.map(delegator_responses, fn {{pool_address, delegator_address, is_active}, response} -> - # staking_response = pool_staking_responses[pool_address] + delegator_reward_response = delegator_reward_responses[{pool_address, delegator_address, is_active}] Map.merge(response, %{ delegator_address_hash: delegator_address, pool_address_hash: pool_address, - is_active: is_active + is_active: is_active, + snapshotted_reward_ratio: delegator_reward_response.delegator_share / 10_000 }) end) {:ok, _} = Chain.import(%{ - staking_pools: %{params: pool_entries}, - staking_pools_delegators: %{params: delegator_entries}, + staking_pools: %{params: pool_entries, on_conflict: staking_pool_on_conflict()}, + staking_pools_delegators: %{params: delegator_entries, on_conflict: staking_pools_delegator_on_conflict()}, timeout: :infinity }) end @@ -165,7 +196,7 @@ defmodule Explorer.Staking.StakeSnapshotting do defp delegator_requests(pool_address, delegator_address, block_number) do [ stake_amount: {:staking, "stakeAmount", [pool_address, delegator_address]}, - snapshotted_staked_amount: {:staking, "stakeAmount", [pool_address, delegator_address], block_number - 1}, + snapshotted_stake_amount: {:staking, "stakeAmount", [pool_address, delegator_address], block_number - 1}, ordered_withdraw: {:staking, "orderedWithdrawAmount", [pool_address, delegator_address]}, max_withdraw_allowed: {:staking, "maxWithdrawAllowed", [pool_address, delegator_address]}, max_ordered_withdraw_allowed: {:staking, "maxWithdrawOrderAllowed", [pool_address, delegator_address]}, @@ -173,6 +204,75 @@ defmodule Explorer.Staking.StakeSnapshotting do ] end + # args = [staking_epoch, validator_staked, total_staked, pool_reward \\ 10_00000] + def pool_reward_requests(args, block_number) do + [ + validator_share: {:block_reward, "validatorShare", args, block_number - 1}, + ] + end + + # args = [staking_epoch, delegator_staked, validator_staked, total_staked, pool_reward \\ 10_00000] + def delegator_reward_requests(args, block_number) do + [ + delegator_share: {:block_reward, "delegatorShare", args, block_number - 1}, + ] + end + + defp staking_pool_on_conflict do + from( + pool in StakingPool, + update: [ + set: [ + mining_address_hash: fragment("EXCLUDED.mining_address_hash"), + delegators_count: fragment("EXCLUDED.delegators_count"), + is_active: fragment("EXCLUDED.is_active"), + is_banned: fragment("EXCLUDED.is_banned"), + is_validator: fragment("EXCLUDED.is_validator"), + 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"), + staked_ratio: fragment("EXCLUDED.staked_ratio"), + snapshotted_staked_ratio: fragment("EXCLUDED.snapshotted_staked_ratio"), + self_staked_amount: fragment("EXCLUDED.self_staked_amount"), + staked_amount: fragment("EXCLUDED.staked_amount"), + snapshotted_self_staked_amount: fragment("EXCLUDED.snapshotted_self_staked_amount"), + snapshotted_staked_amount: fragment("EXCLUDED.snapshotted_staked_amount"), + ban_reason: fragment("EXCLUDED.ban_reason"), + was_banned_count: fragment("EXCLUDED.was_banned_count"), + was_validator_count: fragment("EXCLUDED.was_validator_count"), + is_deleted: fragment("EXCLUDED.is_deleted"), + banned_until: fragment("EXCLUDED.banned_until"), + banned_delegators_until: fragment("EXCLUDED.banned_delegators_until"), + inserted_at: fragment("LEAST(?, EXCLUDED.inserted_at)", pool.inserted_at), + updated_at: fragment("GREATEST(?, EXCLUDED.updated_at)", pool.updated_at) + ] + ] + ) + end + + defp staking_pools_delegator_on_conflict do + from( + delegator in StakingPoolsDelegator, + update: [ + set: [ + stake_amount: fragment("EXCLUDED.stake_amount"), + snapshotted_stake_amount: fragment("EXCLUDED.snapshotted_stake_amount"), + ordered_withdraw: fragment("EXCLUDED.ordered_withdraw"), + max_withdraw_allowed: fragment("EXCLUDED.max_withdraw_allowed"), + max_ordered_withdraw_allowed: fragment("EXCLUDED.max_ordered_withdraw_allowed"), + ordered_withdraw_epoch: fragment("EXCLUDED.ordered_withdraw_epoch"), + reward_ratio: fragment("EXCLUDED.reward_ratio"), + snapshotted_reward_ratio: fragment("EXCLUDED.snapshotted_reward_ratio"), + inserted_at: fragment("LEAST(?, EXCLUDED.inserted_at)", delegator.inserted_at), + updated_at: fragment("GREATEST(?, EXCLUDED.updated_at)", delegator.updated_at), + is_active: fragment("EXCLUDED.is_active"), + is_deleted: fragment("EXCLUDED.is_deleted") + ] + ] + ) + end + defp abi(file_name) do :explorer |> Application.app_dir("priv/contracts_abi/posdao/#{file_name}.json") diff --git a/apps/explorer/priv/contracts_abi/posdao/BlockRewardAuRa.json b/apps/explorer/priv/contracts_abi/posdao/BlockRewardAuRa.json index 1b6076b8b8..6cabc8bcb2 100644 --- a/apps/explorer/priv/contracts_abi/posdao/BlockRewardAuRa.json +++ b/apps/explorer/priv/contracts_abi/posdao/BlockRewardAuRa.json @@ -520,5 +520,71 @@ "payable": false, "stateMutability": "view", "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_stakingEpoch", + "type": "uint256" + }, + { + "name": "_validatorStaked", + "type": "uint256" + }, + { + "name": "_totalStaked", + "type": "uint256" + }, + { + "name": "_poolReward", + "type": "uint256" + } + ], + "name": "validatorShare", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_stakingEpoch", + "type": "uint256" + }, + { + "name": "_delegatorStaked", + "type": "uint256" + }, + { + "name": "_validatorStaked", + "type": "uint256" + }, + { + "name": "_totalStaked", + "type": "uint256" + }, + { + "name": "_poolReward", + "type": "uint256" + } + ], + "name": "delegatorShare", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" } ]