Merge branch 'master' into ab-verify-smart-contracts-with-external-libs

pull/1400/head
Ayrat Badykov 6 years ago committed by GitHub
commit 192674612c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      apps/explorer/config/config.exs
  2. 133
      apps/explorer/lib/explorer/chain/supply/token_bridge.ex
  3. 66
      apps/explorer/test/explorer/chain/supply/token_bridge_test.exs

@ -40,8 +40,8 @@ else
config :explorer, Explorer.Validator.MetadataProcessor, enabled: false
end
if System.get_env("SUPPLY_MODULE") == "TransactionAndLog" do
config :explorer, supply: Explorer.Chain.Supply.TransactionAndLog
if System.get_env("SUPPLY_MODULE") == "TokenBridge" do
config :explorer, supply: Explorer.Chain.Supply.TokenBridge
end
if System.get_env("SOURCE_MODULE") == "TransactionAndLog" do

@ -0,0 +1,133 @@
defmodule Explorer.Chain.Supply.TokenBridge do
@moduledoc """
Defines the supply API for calculating the supply based on Token Bridge.
"""
use Explorer.Chain.Supply
alias Explorer.Chain.Wei
alias Explorer.SmartContract.Reader
@token_bridge_contract_address "0x7301CFA0e1756B71869E93d4e4Dca5c7d0eb0AA6"
@total_burned_coins_abi %{
"type" => "function",
"stateMutability" => "view",
"payable" => false,
"outputs" => [%{"type" => "uint256", "name" => ""}],
"name" => "totalBurntCoins",
"inputs" => [],
"constant" => true
}
@total_burned_coins_params %{"totalBurntCoins" => []}
@block_reward_contract_address "0x867305d19606aadba405ce534e303d0e225f9556"
@total_minted_coins_abi %{
"type" => "function",
"stateMutability" => "view",
"payable" => false,
"outputs" => [%{"type" => "uint256", "name" => ""}],
"name" => "mintedTotally",
"inputs" => [],
"constant" => true
}
@total_minted_coins_params %{"mintedTotally" => []}
@ets_table :token_bridge_contract_coin_cache
# 30 minutes
@cache_period 1_000 * 60 * 30
@cache_key "coins_with_period"
def circulating, do: total_coins()
def total, do: total_coins()
def total_coins(opts \\ []) do
cache_period = Keyword.get(opts, :cache_period) || @cache_period
cached_total_coins(cache_period)
end
defp minted_coins do
address = System.get_env("BLOCK_REWARD_CONTRACT") || @block_reward_contract_address
call_contract(address, @total_minted_coins_abi, @total_minted_coins_params)
end
defp burned_coins do
address = System.get_env("TOKEN_BRIDGE_CONTRACT") || @token_bridge_contract_address
call_contract(address, @total_burned_coins_abi, @total_burned_coins_params)
end
defp call_contract(address, abi, params) do
abi = [abi]
method_name =
params
|> Enum.map(fn {key, _value} -> key end)
|> List.first()
value =
case Reader.query_contract(address, abi, params) do
%{^method_name => {:ok, [result]}} -> result
_ -> 0
end
%Wei{value: Decimal.new(value)}
end
def cached_total_coins(cache_period) do
setup_cache()
{value, cache_time} = cached_values()
if current_time() - cache_time > cache_period do
{current_value, _} = update_cache()
current_value
else
value
end
end
defp cached_values do
cache_key = @cache_key
case :ets.lookup(@ets_table, @cache_key) do
[{^cache_key, {coins, time}}] ->
{coins, time}
_ ->
update_cache()
end
end
defp update_cache do
current_total_coins =
minted_coins()
|> Wei.sub(burned_coins())
|> Wei.to(:ether)
current_time = current_time()
:ets.insert(@ets_table, {@cache_key, {current_total_coins, current_time}})
{current_total_coins, current_time}
end
defp setup_cache do
if :ets.whereis(@ets_table) == :undefined do
:ets.new(@ets_table, [
:set,
:named_table,
:public,
write_concurrency: true
])
end
end
defp current_time do
utc_now = DateTime.utc_now()
DateTime.to_unix(utc_now, :millisecond)
end
end

@ -0,0 +1,66 @@
defmodule Explorer.Chain.Supply.TokenBridgeTest do
use EthereumJSONRPC.Case, async: false
import Mox
alias Explorer.Chain.Supply.TokenBridge
@moduletag :capture_log
setup :set_mox_global
setup :verify_on_exit!
describe "total_coins/1" do
@tag :no_parity
@tag :no_geth
test "calculates total coins", %{json_rpc_named_arguments: json_rpc_named_arguments} do
if json_rpc_named_arguments[:transport] == EthereumJSONRPC.Mox do
EthereumJSONRPC.Mox
|> expect(:json_rpc, fn [
%{
id: "mintedTotally",
method: "eth_call",
params: [
%{data: "0x553a5c85", to: "0x867305d19606aadba405ce534e303d0e225f9556"},
"latest"
]
}
],
_options ->
{:ok,
[
%{
id: "mintedTotally",
jsonrpc: "2.0",
result: "0x00000000000000000000000000000000000000000000042aa8fe57ebb112dcc8"
}
]}
end)
|> expect(:json_rpc, fn [
%{
id: "totalBurntCoins",
jsonrpc: "2.0",
method: "eth_call",
params: [
%{data: "0x0e8162ba", to: "0x7301CFA0e1756B71869E93d4e4Dca5c7d0eb0AA6"},
"latest"
]
}
],
_options ->
{:ok,
[
%{
id: "totalBurntCoins",
jsonrpc: "2.0",
result: "0x00000000000000000000000000000000000000000000033cc192839185166fc6"
}
]}
end)
end
assert Decimal.round(TokenBridge.total_coins(), 2, :down) == Decimal.from_float(4388.55)
end
end
end
Loading…
Cancel
Save