Replace eth_getLogs with public getter

staking
Vadim 5 years ago committed by Victor Baranov
parent 2040ea32eb
commit 4c1a352d75
  1. 90
      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_title.html.eex
  3. 12
      apps/explorer/lib/explorer/staking/contract_reader.ex
  4. 46
      apps/explorer/priv/contracts_abi/posdao/StakingAuRa.json

@ -361,32 +361,29 @@ defmodule BlockScoutWeb.StakesChannel do
def find_claim_reward_pools(socket, staker, staking_contract_address) do
:ets.insert(ContractState, {claim_reward_long_op_key(staker), true})
try do
staker_padded = address_pad_to_64(staker)
json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments)
staking_contract = ContractState.get(:staking_contract)
# Search for `PlacedStake` events
{error, pools_staked_into} = find_claim_reward_pools_by_logs(staking_contract_address, [
# keccak-256 of `PlacedStake(address,address,uint256,uint256)`
"0x2273de02cb1f69ba6259d22c4bc22c60e4c94c193265ef6afee324a04a9b6d22",
nil, # don't filter by `toPoolStakingAddress`
"0x" <> staker_padded # filter by `staker`
], json_rpc_named_arguments)
# Search for `MovedStake` events
{error, pools_moved_into} = if error == nil do
find_claim_reward_pools_by_logs(staking_contract_address, [
# keccak-256 of `MovedStake(address,address,address,uint256,uint256)`
"0x4480d8e4b1e9095b94bf513961d26fe1d32386ebdd103d18fe8738cf4b2223ff",
nil, # don't filter by `toPoolStakingAddress`
"0x" <> staker_padded # filter by `staker`
], json_rpc_named_arguments)
responses =
ContractReader.get_staker_pools_length_request(staker)
|> ContractReader.perform_requests(%{staking: staking_contract.address}, staking_contract.abi)
staker_pools_length = responses[:length]
chunk_size = 100
pools = if staker_pools_length > 0 do
chunks = 0..trunc(ceil(staker_pools_length / chunk_size) - 1)
Enum.reduce(chunks, [], fn i, acc ->
responses =
ContractReader.get_staker_pools_request(staker, i * chunk_size, chunk_size)
|> ContractReader.perform_requests(%{staking: staking_contract.address}, staking_contract.abi)
acc ++ Enum.map(responses[:pools], fn pool_staking_address ->
address_bytes_to_string(pool_staking_address)
end)
end)
else
{error, []}
[]
end
{error, pools} = if error == nil do
pools = Enum.uniq(pools_staked_into ++ pools_moved_into)
pools_amounts = Enum.map(pools, fn pool_staking_address ->
ContractReader.call_get_reward_amount(
staking_contract_address,
@ -462,11 +459,6 @@ defmodule BlockScoutWeb.StakesChannel do
{error, pools}
end
{error, pools}
else
{error, %{}}
end
html = View.render_to_string(
StakesView,
"_stakes_modal_claim_reward_content.html",
@ -548,47 +540,7 @@ defmodule BlockScoutWeb.StakesChannel do
end
end
defp find_claim_reward_pools_by_logs(staking_contract_address, topics, json_rpc_named_arguments) do
latest_block = BlockNumber.get_max()
split_by = 500 # must be less than 1000
iterations = 0..trunc(ceil(latest_block / split_by) - 1)
Enum.reduce(iterations, {nil, []}, fn i, acc ->
{acc_error, acc_pools} = acc
if acc_error do
{acc_error, []}
else
from = i * split_by + 1
to = (i + 1) * split_by
to = if to > latest_block, do: latest_block, else: to
result = EthereumJSONRPC.request(%{
id: 0,
method: "eth_getLogs",
params: [%{
fromBlock: "0x" <> Integer.to_string(from, 16),
toBlock: "0x" <> Integer.to_string(to, 16),
address: staking_contract_address,
topics: topics
}]
}) |> EthereumJSONRPC.json_rpc(json_rpc_named_arguments)
case result do
{:ok, response} ->
pools = Enum.uniq(acc_pools ++ Enum.map(response, fn event ->
truncate_address(Enum.at(event["topics"], 1))
end))
{acc_error, pools}
{:error, reason} ->
{error_reason_to_string(reason), []}
end
end
end)
end
defp address_pad_to_64(address) do
address
|> String.replace_leading("0x", "")
|> String.pad_leading(64, ["0"])
end
defp address_bytes_to_string(hash), do: "0x" <> Base.encode16(hash, case: :lower)
defp array_to_ranges(numbers, prev_ranges \\ []) do
length = Enum.count(numbers)
@ -647,8 +599,4 @@ defmodule BlockScoutWeb.StakesChannel do
staker = if staker == nil, do: "", else: staker
Atom.to_string(@claim_reward_long_op) <> "_" <> staker
end
defp truncate_address("0x000000000000000000000000" <> truncated_address) do
"0x#{truncated_address}"
end
end

@ -11,7 +11,7 @@
<div class="check card-title-control">
<input type="checkbox" pool-filter-my />
<div class="check-icon"></div>
<div class="check-text"><%= gettext("Show only those I staked into") %></div>
<div class="check-text"><%= gettext("Show only those I have stake in") %></div>
</div>
</div>
</div>

@ -162,6 +162,18 @@ defmodule Explorer.Staking.ContractReader do
]
end
def get_staker_pools_request(staker, offset, length) do
[
pools: {:staking, "getStakerPools", [staker, offset, length]}
]
end
def get_staker_pools_length_request(staker) do
[
length: {:staking, "getStakerPoolsLength", [staker]}
]
end
def pool_staking_requests(staking_address, block_number) do
[
active_delegators: active_delegators_request(staking_address, block_number)[:active_delegators],

@ -36,6 +36,52 @@
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_staker",
"type": "address"
},
{
"name": "_offset",
"type": "uint256"
},
{
"name": "_length",
"type": "uint256"
}
],
"name": "getStakerPools",
"outputs": [
{
"name": "result",
"type": "address[]"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_staker",
"type": "address"
}
],
"name": "getStakerPoolsLength",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [

Loading…
Cancel
Save