Add changes to support force email verification (#7298)

* Add changes to support force email verification

* Fix gettext; Add 'Unverified email' unauthorized response

* Changelog; Change http code: 401 -> 403

* Add chain_id to redis key for auth0 token

* Add resend interval; Add possibility to log out

* Add check if My Account enabled for the unverified email banner
pull/7378/merge
nikitosing 2 years ago committed by GitHub
parent 921137818e
commit ce9d67a7d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 6
      apps/block_scout_web/assets/css/main-page.scss
  3. 9
      apps/block_scout_web/assets/js/lib/modals.js
  4. 1
      apps/block_scout_web/assets/js/lib/public_tags_request_form.js
  5. 24
      apps/block_scout_web/assets/js/pages/chain.js
  6. 6
      apps/block_scout_web/lib/block_scout_web/api_router.ex
  7. 2
      apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/authenticate_controller.ex
  8. 64
      apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/email_controller.ex
  9. 20
      apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/fallback_controller.ex
  10. 4
      apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/tags_controller.ex
  11. 50
      apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/user_controller.ex
  12. 12
      apps/block_scout_web/lib/block_scout_web/controllers/account/auth_controller.ex
  13. 39
      apps/block_scout_web/lib/block_scout_web/models/user_from_auth.ex
  14. 8
      apps/block_scout_web/lib/block_scout_web/templates/layout/_account_menu_item.html.eex
  15. 10
      apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex
  16. 435
      apps/block_scout_web/priv/gettext/default.pot
  17. 435
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  18. 3
      apps/explorer/lib/explorer/account/identity.ex
  19. 48
      apps/explorer/lib/explorer/third_party_integrations/auth0.ex
  20. 9
      apps/explorer/priv/account/migrations/20230502083519_add_verification_email_sent_at.exs
  21. 3
      config/runtime.exs
  22. 1
      docker-compose/envs/common-blockscout.env
  23. 3
      docker/Makefile

@ -4,6 +4,7 @@
### Features
- [#7298](https://github.com/blockscout/blockscout/pull/7298) - Add changes to support force email verification
- [#7416](https://github.com/blockscout/blockscout/pull/7416) - Add option to disable reCAPTCHA
- [#6694](https://github.com/blockscout/blockscout/pull/6694) - Add withdrawals support (EIP-4895)
- [#7355](https://github.com/blockscout/blockscout/pull/7355) - Add endpoint for token info import

@ -5,6 +5,11 @@
display: none;
}
a.disabled {
pointer-events: none;
opacity: 0.65;
}
/* This file is for your main application css. */
// Bootstrap Core CSS
@ -14,6 +19,7 @@
@import "theme/variables";
@import "~bootstrap/scss/close";
@import "~bootstrap/scss/root";
@import "~bootstrap/scss/reboot";
@import "~bootstrap/scss/grid";

@ -25,7 +25,7 @@ export function currentModal () {
return $currentModal
}
export function openModal ($modal, unclosable) {
export function openModal ($modal, unclosable, onHideCallback = null) {
// Hide all tooltips before showing a modal,
// since they are sticking on top of modal
$('.tooltip').tooltip('hide')
@ -54,6 +54,9 @@ export function openModal ($modal, unclosable) {
modalLocked = true
}
}
if (onHideCallback) {
$($currentModal).on('hidden.bs.modal', onHideCallback)
}
}
export function openModalWithMessage ($modal, unclosable, message) {
@ -116,11 +119,11 @@ export function openWarningModal (title, text) {
openModal($modal)
}
export function openSuccessModal (title, text) {
export function openSuccessModal (title, text, callback = null) {
const $modal = $('#successStatusModal')
$modal.find('.modal-status-title').text(title)
$modal.find('.modal-status-text').html(text)
openModal($modal)
openModal($modal, false, callback)
}
export function openQuestionModal (title, text, acceptCallback = null, exceptCallback = null, acceptText = 'Yes', exceptText = 'No') {

@ -11,7 +11,6 @@ if (index <= 1) {
$('.add-form-field').on('click', (event) => {
event.preventDefault()
console.log(event)
const $container = $('#' + event.currentTarget.dataset.container)
// @ts-ignore
const index = parseInt($container[0].dataset.index)

@ -12,6 +12,7 @@ import { createStore, connectElements } from '../lib/redux_helpers.js'
import { batchChannel, showLoader } from '../lib/utils'
import listMorph from '../lib/list_morph'
import '../app'
import { openErrorModal, openSuccessModal, openWarningModal } from '../lib/modals'
const BATCH_THRESHOLD = 6
const BLOCKS_PER_PAGE = 4
@ -418,3 +419,26 @@ function loadBlocks (store) {
function bindBlockErrorMessage (store) {
$('[data-selector="chain-block-list"] [data-selector="error-message"]').on('click', _event => loadBlocks(store))
}
$('a.ajax').on('click', (event) => {
event.preventDefault()
event.currentTarget.classList.add('disabled')
$.get($(event.currentTarget).attr('href'), () => {
openSuccessModal('Success', 'Email successfully resent', () => { window.location.reload() })
}).fail((error) => {
if (error.responseJSON && error.responseJSON.message) {
if (error.status === 429) {
openWarningModal('Warning', error.responseJSON.message)
} else {
openErrorModal('Error', error.responseJSON.message, false)
}
} else {
openErrorModal('Error', 'Email resend failed', false)
}
})
.always(() => {
event.currentTarget.classList.remove('disabled')
})
}
)

@ -46,7 +46,7 @@ defmodule BlockScoutWeb.ApiRouter do
plug(RateLimit)
end
alias BlockScoutWeb.Account.Api.V1.{AuthenticateController, TagsController, UserController}
alias BlockScoutWeb.Account.Api.V1.{AuthenticateController, EmailController, TagsController, UserController}
alias BlockScoutWeb.API.V2
scope "/account/v1", as: :account_v1 do
@ -58,6 +58,10 @@ defmodule BlockScoutWeb.ApiRouter do
get("/get_csrf", UserController, :get_csrf)
scope "/email" do
get("/resend", EmailController, :resend_email)
end
scope "/user" do
get("/info", UserController, :info)

@ -21,7 +21,7 @@ defmodule BlockScoutWeb.Account.Api.V1.AuthenticateController do
{:sensitive_endpoints_api_key, Application.get_env(:block_scout_web, :sensitive_endpoints_api_key)},
{:api_key, ^api_key} <- {:api_key, params["api_key"]},
{:auth, %{id: uid} = current_user} <- {:auth, current_user(conn)},
{:identity, [%Identity{}]} <- {:identity, UserFromAuth.find_identity(uid)} do
{:identity, %Identity{}} <- {:identity, UserFromAuth.find_identity(uid)} do
conn
|> put_status(200)
|> json(current_user)

@ -0,0 +1,64 @@
defmodule BlockScoutWeb.Account.Api.V1.EmailController do
use BlockScoutWeb, :controller
alias BlockScoutWeb.Models.UserFromAuth
alias Explorer.Account.Identity
alias Explorer.Repo
alias Explorer.ThirdPartyIntegrations.Auth0
require Logger
action_fallback(BlockScoutWeb.Account.Api.V1.FallbackController)
def resend_email(conn, _params) do
with user <- get_session(conn, :current_user),
{:auth, false} <- {:auth, is_nil(user)},
{:email_verified, false} <- {:email_verified, user[:email_verified]},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(user[:id])},
{:interval, true} <- {:interval, check_time_interval(identity.verification_email_sent_at)} do
domain = Application.get_env(:ueberauth, Ueberauth.Strategy.Auth0.OAuth)[:domain]
api_key = Auth0.get_m2m_jwt()
headers = [{"Authorization", "Bearer #{api_key}"}, {"Content-Type", "application/json"}]
url = "https://#{domain}/api/v2/jobs/verification-email"
body = %{
"user_id" => user.uid
}
case HTTPoison.post(url, Jason.encode!(body), headers, []) do
{:ok, %HTTPoison.Response{body: _body, status_code: 201}} ->
identity
|> Identity.changeset(%{verification_email_sent_at: DateTime.utc_now()})
|> Repo.account_repo().update()
conn
|> configure_session(drop: true)
|> json(%{message: "Success"})
other ->
Logger.error(fn -> ["Error while sending verification email: ", inspect(other)] end)
conn
|> put_status(500)
|> json(%{message: "Unexpected error"})
end
end
end
def check_time_interval(nil), do: true
def check_time_interval(sent_at) do
interval = Application.get_env(:explorer, Explorer.Account)[:resend_interval]
now = DateTime.utc_now()
if sent_at
|> DateTime.add(interval, :millisecond)
|> DateTime.compare(now) != :gt do
true
else
sent_at
|> DateTime.add(interval, :millisecond)
|> DateTime.diff(now, :second)
end
end
end

@ -75,10 +75,12 @@ defmodule BlockScoutWeb.Account.Api.V1.FallbackController do
end
def call(conn, {:auth, _}) do
current_user = get_session(conn, :current_user)
conn
|> put_status(:unauthorized)
|> put_status(if(current_user, do: :forbidden, else: :unauthorized))
|> put_view(UserView)
|> render(:message, %{message: "Unauthorized"})
|> render(:message, %{message: if(current_user, do: "Unverified email", else: "Unauthorized")})
end
def call(conn, {:api_key, _}) do
@ -94,4 +96,18 @@ defmodule BlockScoutWeb.Account.Api.V1.FallbackController do
|> put_view(UserView)
|> render(:message, %{message: "API key not configured on the server"})
end
def call(conn, {:email_verified, _}) do
conn
|> put_status(:not_found)
|> put_view(UserView)
|> render(:message, %{message: "Your email address already verified"})
end
def call(conn, {:interval, remain}) do
conn
|> put_status(:too_many_requests)
|> put_view(UserView)
|> render(:message, %{message: "Email resend is available in #{remain} seconds."})
end
end

@ -17,7 +17,7 @@ defmodule BlockScoutWeb.Account.Api.V1.TagsController do
else
uid = current_user(conn).id
with {:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
with {:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{:watchlist, %{watchlists: [watchlist | _]}} <-
{:watchlist, Repo.account_repo().preload(identity, :watchlists)},
{:address_hash, {:ok, address_hash}} <- {:address_hash, Address.cast(address_hash)} do
@ -58,7 +58,7 @@ defmodule BlockScoutWeb.Account.Api.V1.TagsController do
else
uid = current_user(conn).id
with {:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
with {:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{:watchlist, %{watchlists: [watchlist | _]}} <-
{:watchlist, Repo.account_repo().preload(identity, :watchlists)},
false <- is_nil(transaction) do

@ -18,7 +18,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def info(conn, _params) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)} do
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)} do
conn
|> put_status(200)
|> render(:user_info, %{identity: identity})
@ -27,7 +27,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def watchlist(conn, _params) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{:watchlist, %{watchlists: [watchlist | _]}} <-
{:watchlist, Repo.account_repo().preload(identity, :watchlists)},
watchlist_with_addresses <- preload_watchlist_addresses(watchlist) do
@ -42,7 +42,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def delete_watchlist(conn, %{"id" => watchlist_address_id}) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{:watchlist, %{watchlists: [watchlist | _]}} <-
{:watchlist, Repo.account_repo().preload(identity, :watchlists)},
{count, _} <- WatchlistAddress.delete(watchlist_address_id, watchlist.id),
@ -94,7 +94,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
}
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{:watchlist, %{watchlists: [watchlist | _]}} <-
{:watchlist, Repo.account_repo().preload(identity, :watchlists)},
{:ok, watchlist_address} <-
@ -151,7 +151,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
}
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{:watchlist, %{watchlists: [watchlist | _]}} <-
{:watchlist, Repo.account_repo().preload(identity, :watchlists)},
{:ok, watchlist_address} <-
@ -167,7 +167,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def tags_address(conn, _params) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
address_tags <- TagAddress.get_tags_address_by_identity_id(identity.id) do
conn
|> put_status(200)
@ -177,7 +177,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def delete_tag_address(conn, %{"id" => tag_id}) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{count, _} <- TagAddress.delete(tag_id, identity.id),
{:tag_delete, true} <- {:tag_delete, count > 0} do
conn
@ -188,7 +188,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def create_tag_address(conn, %{"address_hash" => address_hash, "name" => name}) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{:ok, address_tag} <-
TagAddress.create(%{
name: name,
@ -203,7 +203,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def update_tag_address(conn, %{"id" => tag_id} = attrs) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{:ok, address_tag} <-
TagAddress.update(
reject_nil_map_values(%{
@ -221,7 +221,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def tags_transaction(conn, _params) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
transaction_tags <- TagTransaction.get_tags_transaction_by_identity_id(identity.id) do
conn
|> put_status(200)
@ -231,7 +231,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def delete_tag_transaction(conn, %{"id" => tag_id}) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{count, _} <- TagTransaction.delete(tag_id, identity.id),
{:tag_delete, true} <- {:tag_delete, count > 0} do
conn
@ -242,7 +242,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def create_tag_transaction(conn, %{"transaction_hash" => tx_hash, "name" => name}) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{:ok, transaction_tag} <-
TagTransaction.create(%{
name: name,
@ -257,7 +257,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def update_tag_transaction(conn, %{"id" => tag_id} = attrs) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{:ok, transaction_tag} <-
TagTransaction.update(
reject_nil_map_values(%{
@ -275,7 +275,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def api_keys(conn, _params) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
api_keys <- ApiKey.get_api_keys_by_identity_id(identity.id) do
conn
|> put_status(200)
@ -285,7 +285,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def delete_api_key(conn, %{"api_key" => api_key_uuid}) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{count, _} <- ApiKey.delete(api_key_uuid, identity.id),
{:api_key_delete, true} <- {:api_key_delete, count > 0} do
conn
@ -296,7 +296,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def create_api_key(conn, %{"name" => api_key_name}) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{:ok, api_key} <-
ApiKey.create(%{name: api_key_name, identity_id: identity.id}) do
conn
@ -307,7 +307,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def update_api_key(conn, %{"name" => api_key_name, "api_key" => api_key_value}) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{:ok, api_key} <-
ApiKey.update(%{value: api_key_value, name: api_key_name, identity_id: identity.id}) do
conn
@ -318,7 +318,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def custom_abis(conn, _params) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
custom_abis <- CustomABI.get_custom_abis_by_identity_id(identity.id) do
conn
|> put_status(200)
@ -328,7 +328,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def delete_custom_abi(conn, %{"id" => id}) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{count, _} <- CustomABI.delete(id, identity.id),
{:custom_abi_delete, true} <- {:custom_abi_delete, count > 0} do
conn
@ -339,7 +339,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def create_custom_abi(conn, %{"contract_address_hash" => contract_address_hash, "name" => name, "abi" => abi}) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{:ok, custom_abi} <-
CustomABI.create(%{
name: name,
@ -360,7 +360,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
} = params
) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{:ok, custom_abi} <-
CustomABI.update(
reject_nil_map_values(%{
@ -379,7 +379,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def public_tags_requests(conn, _params) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
public_tags_requests <- PublicTagsRequest.get_public_tags_requests_by_identity_id(identity.id) do
conn
|> put_status(200)
@ -389,7 +389,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def delete_public_tags_request(conn, %{"id" => id, "remove_reason" => remove_reason}) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{:public_tag_delete, true} <-
{:public_tag_delete,
PublicTagsRequest.mark_as_deleted_public_tags_request(%{
@ -405,7 +405,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
def create_public_tags_request(conn, params) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{:ok, public_tags_request} <-
PublicTagsRequest.create(%{
full_name: params["full_name"],
@ -431,7 +431,7 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do
} = params
) do
with {:auth, %{id: uid}} <- {:auth, current_user(conn)},
{:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)},
{:identity, %Identity{} = identity} <- {:identity, UserFromAuth.find_identity(uid)},
{:ok, public_tags_request} <-
PublicTagsRequest.update(
reject_nil_map_values(%{

@ -35,6 +35,11 @@ defmodule BlockScoutWeb.Account.AuthController do
def callback(%{assigns: %{ueberauth_auth: auth}} = conn, params) do
case UserFromAuth.find_or_create(auth) do
{:ok, %{email_verified: false} = user} ->
conn
|> put_session(:current_user, user)
|> redirect(to: root())
{:ok, user} ->
CSRFProtection.get_csrf_token()
@ -60,7 +65,9 @@ defmodule BlockScoutWeb.Account.AuthController do
def current_user(%{private: %{plug_session: %{"current_user" => _}}} = conn) do
if Account.enabled?() do
get_session(conn, :current_user)
conn
|> get_session(:current_user)
|> check_email_verification()
else
nil
end
@ -68,6 +75,9 @@ defmodule BlockScoutWeb.Account.AuthController do
def current_user(_), do: nil
defp check_email_verification(%{email_verified: true} = session), do: session
defp check_email_verification(_), do: nil
defp root do
ConfigHelper.network_path()
end

@ -11,31 +11,23 @@ defmodule BlockScoutWeb.Models.UserFromAuth do
import Ecto.Query, only: [from: 2]
def find_or_create(%Auth{} = auth, api_call? \\ false) do
def find_or_create(%Auth{} = auth) do
case find_identity(auth) do
[] ->
nil ->
case create_identity(auth) do
%Identity{} = identity ->
{:ok, return_value(identity, auth, api_call?)}
{:ok, session_info(auth, identity)}
{:error, changeset} ->
{:error, changeset}
end
[%{} = identity | _] ->
%{} = identity ->
update_identity(identity, update_identity_map(auth))
{:ok, return_value(identity, auth, api_call?)}
{:ok, session_info(auth, identity)}
end
end
defp return_value(identity, _auth, true) do
identity
end
defp return_value(identity, auth, false) do
basic_info(auth, identity)
end
defp create_identity(auth) do
with {:ok, %Identity{} = identity} <- Repo.account_repo().insert(new_identity(auth)),
{:ok, _watchlist} <- add_watchlist(identity) do
@ -68,7 +60,7 @@ defmodule BlockScoutWeb.Models.UserFromAuth do
end
def find_identity(auth_or_uid) do
Repo.account_repo().all(query_identity(auth_or_uid))
Repo.account_repo().one(query_identity(auth_or_uid))
end
def query_identity(%Auth{} = auth) do
@ -79,7 +71,21 @@ defmodule BlockScoutWeb.Models.UserFromAuth do
from(i in Identity, where: i.id == ^id)
end
defp basic_info(auth, identity) do
defp session_info(
%Auth{extra: %Ueberauth.Auth.Extra{raw_info: %{user: %{"email_verified" => false}}}} = auth,
identity
) do
%{
id: identity.id,
uid: auth.uid,
email: email_from_auth(auth),
nickname: nickname_from_auth(auth),
avatar: avatar_from_auth(auth),
email_verified: false
}
end
defp session_info(auth, identity) do
%{watchlists: [watchlist | _]} = Repo.account_repo().preload(identity, :watchlists)
%{
@ -89,7 +95,8 @@ defmodule BlockScoutWeb.Models.UserFromAuth do
name: name_from_auth(auth),
nickname: nickname_from_auth(auth),
avatar: avatar_from_auth(auth),
watchlist_id: watchlist.id
watchlist_id: watchlist.id,
email_verified: true
}
end

@ -3,13 +3,14 @@
<li class="nav-item dropdown">
<a class="nav-link topnav-nav-link dropdown-toggle" href="#" id="navbarBlocksDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="nav-link-icon">
<img src="<%= Plug.Conn.get_session(@conn, :current_user)[:avatar] %>" size="20" height="20" width="20" >
<img src="<%= @current_user[:avatar] %>" size="20" height="20" width="20" >
</span>
</a>
<div class="dropdown-menu" aria-labelledby="navbarBlocksDropdown">
<div class="header dropdown-item">
<%= gettext("Signed in as ") <> Plug.Conn.get_session(@conn, :current_user)[:nickname] %>
<%= gettext("Signed in as ") <> @current_user[:nickname] %>
</div>
<%= if @current_user[:email_verified] do %>
<a href="<%= auth_path(@conn, :profile) %>" class= "profile-button dropdown-item"><%= gettext "Profile" %></a>
<a href="<%= watchlist_path(@conn, :show) %>" class= "watchlist-button dropdown-item"><%= gettext "Watch list" %></a>
<a href="<%= tag_address_path(@conn, :index) %>" class= "address-tags-button dropdown-item"><%= gettext "Address Tags" %></a>
@ -17,6 +18,9 @@
<a href="<%= api_key_path(@conn, :index) %>" class= "api-keys-button dropdown-item"><%= gettext "API keys" %></a>
<a href="<%= custom_abi_path(@conn, :index) %>" class= "custom-abi-button dropdown-item"><%= gettext "Custom ABI" %></a>
<a href="<%= public_tags_request_path(@conn, :index) %>" class= "public-tags-button dropdown-item"><%= gettext "Public Tags" %></a>
<% else %>
<p class="alert alert-warning" role="alert" style="margin-bottom: 0"><%= gettext("Please confirm your email address to use the My Account feature.") %></p>
<% end %>
<a href="<%= BlockScoutWeb.LayoutView.sign_out_link %>" class= "sign-out-button dropdown-item"><%= gettext "Sign out" %></a>
</div>
</li>

@ -91,11 +91,15 @@
</div>
<% end %>
<% end %>
<%= render BlockScoutWeb.LayoutView, "_topnav.html", current_user: Conn.get_session(@conn, :current_user), conn: @conn %>
<main class="js-ad-dependant-pt pt-5">
<% session = Explorer.Account.enabled?() && Plug.Conn.get_session(@conn, :current_user) %>
<%= render BlockScoutWeb.LayoutView, "_topnav.html", current_user: session, conn: @conn %>
<%= if session && !session[:email_verified] do %>
<p class="alert alert-warning" role="alert" style="margin-bottom: 0"><%= gettext("Please confirm your email address to use the My Account feature.") %> <%= gettext("A confirmation email was sent to") %> <a href="mailto:<%= session[:email] %>"><%=session[:email] %></a> <%= gettext "on sign up. Didn’t receive?" %> <a href="/api/account/v1/email/resend" class="ajax"><%= gettext "Resend verification email" %></a>.</p>
<% else %>
<p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
<% end %>
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
<main class="js-ad-dependant-pt pt-5">
<%= @inner_content %>
</main>
<%= render BlockScoutWeb.LayoutView, "_footer.html", assigns %>

@ -53,6 +53,11 @@ msgstr ""
msgid "%{count} Transactions"
msgstr ""
#: lib/block_scout_web/templates/transaction/_actions.html.eex:101
#, elixir-autogen, elixir-format
msgid "%{qty} of <span class=\"text-muted\">Token ID [%{link_to_id}]</span>"
msgstr ""
#: lib/block_scout_web/templates/chain/_metatags.html.eex:2
#, elixir-autogen, elixir-format
msgid "%{subnetwork} %{network} Explorer"
@ -86,6 +91,26 @@ msgstr ""
msgid "- We're indexing this chain right now. Some of the counts may be inaccurate."
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:8
#, elixir-autogen, elixir-format
msgid "1. If you have just submitted this transaction please wait for at least 30 seconds before refreshing this page."
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:9
#, elixir-autogen, elixir-format
msgid "2. It could still be in the TX Pool of a different node, waiting to be broadcasted."
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:10
#, elixir-autogen, elixir-format
msgid "3. During times when the network is busy (i.e during ICOs) it can take a while for your transaction to propagate through the network and for us to index it."
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:11
#, elixir-autogen, elixir-format
msgid "4. If it still does not show up after 1 hour, please check with your sender/exchange/wallet/transaction provider for additional information."
msgstr ""
#: lib/block_scout_web/templates/block/overview.html.eex:195
#, elixir-autogen, elixir-format
msgid "64-bit hash of value verifying proof-of-work (note: null for POA chains)."
@ -97,6 +122,11 @@ msgstr ""
msgid "A block producer who successfully included the block onto the blockchain."
msgstr ""
#: lib/block_scout_web/templates/layout/app.html.eex:97
#, elixir-autogen, elixir-format
msgid "A confirmation email was sent to"
msgstr ""
#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:4
#, elixir-autogen, elixir-format
msgid "A library name called in the .sol file. Multiple libraries (up to "
@ -147,7 +177,7 @@ msgstr ""
#: lib/block_scout_web/templates/account/api_key/index.html.eex:7
#: lib/block_scout_web/templates/account/common/_nav.html.eex:16
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:17
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:18
#, elixir-autogen, elixir-format
msgid "API keys"
msgstr ""
@ -252,7 +282,7 @@ msgstr ""
#: lib/block_scout_web/templates/account/common/_nav.html.eex:10
#: lib/block_scout_web/templates/account/tag_address/index.html.eex:7
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:15
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:16
#, elixir-autogen, elixir-format
msgid "Address Tags"
msgstr ""
@ -282,6 +312,12 @@ msgstr ""
msgid "Addresses"
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:38
#: lib/block_scout_web/templates/withdrawal/index.html.eex:35
#, elixir-autogen, elixir-format
msgid "Age"
msgstr ""
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:26
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:28
#: lib/block_scout_web/templates/address_transaction/index.html.eex:22
@ -310,6 +346,13 @@ msgstr ""
msgid "All tokens in the account and total value."
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:41
#: lib/block_scout_web/templates/block_withdrawal/index.html.eex:32
#: lib/block_scout_web/templates/withdrawal/index.html.eex:38
#, elixir-autogen, elixir-format
msgid "Amount"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:437
#, elixir-autogen, elixir-format
msgid "Amount of"
@ -320,6 +363,11 @@ msgstr ""
msgid "Amount of distributed reward. Miners receive a static block reward + Tx fees + uncle fees."
msgstr ""
#: lib/block_scout_web/templates/internal_server_error/index.html.eex:8
#, elixir-autogen, elixir-format
msgid "An unexpected error has occurred. Try reloading the page, or come back soon and try again."
msgstr ""
#: lib/block_scout_web/templates/api_docs/eth_rpc.html.eex:15
#, elixir-autogen, elixir-format
msgid "Anything not in this list is not supported. Click on the method to be taken to the documentation for that method, and check the notes section for any potential differences."
@ -365,6 +413,14 @@ msgstr ""
msgid "Back to Watch list (Cancel)"
msgstr ""
#: lib/block_scout_web/templates/error422/index.html.eex:9
#: lib/block_scout_web/templates/internal_server_error/index.html.eex:9
#: lib/block_scout_web/templates/page_not_found/index.html.eex:9
#: lib/block_scout_web/templates/transaction/not_found.html.eex:13
#, elixir-autogen, elixir-format
msgid "Back to home"
msgstr ""
#: lib/block_scout_web/templates/account/watchlist/show.html.eex:24
#: lib/block_scout_web/templates/address/overview.html.eex:150
#: lib/block_scout_web/templates/address_token/overview.html.eex:51
@ -399,6 +455,16 @@ msgstr ""
msgid "Base URL:"
msgstr ""
#: lib/block_scout_web/templates/withdrawal/_metatags.html.eex:2
#, elixir-autogen, elixir-format
msgid "Beacon chain withdrawals - %{subnetwork} Explorer"
msgstr ""
#: lib/block_scout_web/templates/withdrawal/_metatags.html.eex:7
#, elixir-autogen, elixir-format
msgid "Beacon chain, Withdrawals, %{subnetwork}, %{coin}"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:472
#, elixir-autogen, elixir-format
msgid "Binary data included with the transaction. See input / logs below for additional info."
@ -565,6 +631,11 @@ msgstr ""
msgid "Chore Reward"
msgstr ""
#: lib/block_scout_web/templates/tokens/index.html.eex:38
#, elixir-autogen, elixir-format
msgid "Circulating Market Cap"
msgstr ""
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:137
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:106
#, elixir-autogen, elixir-format
@ -962,7 +1033,7 @@ msgstr ""
#: lib/block_scout_web/templates/account/common/_nav.html.eex:19
#: lib/block_scout_web/templates/account/custom_abi/form.html.eex:8
#: lib/block_scout_web/templates/account/custom_abi/index.html.eex:7
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:18
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:19
#, elixir-autogen, elixir-format
msgid "Custom ABI"
msgstr ""
@ -1429,11 +1500,21 @@ msgstr ""
msgid "Hex (Default)"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:204
#, elixir-autogen, elixir-format
msgid "Highlighted events of the transaction."
msgstr ""
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:108
#, elixir-autogen, elixir-format
msgid "Holders"
msgstr ""
#: lib/block_scout_web/templates/tokens/index.html.eex:48
#, elixir-autogen, elixir-format
msgid "Holders Count"
msgstr ""
#: lib/block_scout_web/templates/api_docs/eth_rpc.html.eex:11
#, elixir-autogen, elixir-format
msgid "However, in general, the"
@ -1478,6 +1559,13 @@ msgstr ""
msgid "Incoming"
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:29
#: lib/block_scout_web/templates/block_withdrawal/index.html.eex:23
#: lib/block_scout_web/templates/withdrawal/index.html.eex:23
#, elixir-autogen, elixir-format
msgid "Index"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:464
#, elixir-autogen, elixir-format
msgid "Index position of Transaction in the block."
@ -1518,6 +1606,11 @@ msgstr ""
msgid "Internal Transactions"
msgstr ""
#: lib/block_scout_web/templates/internal_server_error/index.html.eex:7
#, elixir-autogen, elixir-format
msgid "Internal server error"
msgstr ""
#: lib/block_scout_web/templates/tokens/inventory/index.html.eex:16
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:19
#: lib/block_scout_web/views/tokens/overview_view.ex:42
@ -1709,6 +1802,11 @@ msgstr ""
msgid "Minimum fee required per unit of gas. Fee adjusts based on network congestion."
msgstr ""
#: lib/block_scout_web/templates/transaction/_actions.html.eex:92
#, elixir-autogen, elixir-format
msgid "Mint of %{address} <span class=\"text-muted\">To</span> %{to}"
msgstr ""
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:223
#, elixir-autogen, elixir-format
msgid "Model"
@ -1984,6 +2082,12 @@ msgstr ""
msgid "Play"
msgstr ""
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:22
#: lib/block_scout_web/templates/layout/app.html.eex:97
#, elixir-autogen, elixir-format
msgid "Please confirm your email address to use the My Account feature."
msgstr ""
#: lib/block_scout_web/templates/account/watchlist_address/form.html.eex:68
#, elixir-autogen, elixir-format
msgid "Please select notification methods:"
@ -2004,6 +2108,11 @@ msgstr ""
msgid "Position %{index}"
msgstr ""
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:18
#, elixir-autogen, elixir-format
msgid "Potential matches from contract method database:"
msgstr ""
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:32
#, elixir-autogen, elixir-format
msgid "Potential matches from our contract method database:"
@ -2043,12 +2152,12 @@ msgid "Priority Fees"
msgstr ""
#: lib/block_scout_web/templates/account/common/_nav.html.eex:4
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:13
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:14
#, elixir-autogen, elixir-format
msgid "Profile"
msgstr ""
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:19
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:20
#, elixir-autogen, elixir-format
msgid "Public Tags"
msgstr ""
@ -2139,6 +2248,11 @@ msgstr ""
msgid "Request a public tag/label"
msgstr ""
#: lib/block_scout_web/templates/error422/index.html.eex:7
#, elixir-autogen, elixir-format
msgid "Request cannot be processed"
msgstr ""
#: lib/block_scout_web/templates/account/public_tags_request/index.html.eex:37
#, elixir-autogen, elixir-format
msgid "Request to add public tag"
@ -2149,6 +2263,11 @@ msgstr ""
msgid "Request to edit a public tag/label"
msgstr ""
#: lib/block_scout_web/templates/layout/app.html.eex:97
#, elixir-autogen, elixir-format
msgid "Resend verification email"
msgstr ""
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:112
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:38
#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:104
@ -2201,6 +2320,11 @@ msgstr ""
msgid "Save"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:206
#, elixir-autogen, elixir-format
msgid "Scroll to see more"
msgstr ""
#: lib/block_scout_web/templates/address_logs/index.html.eex:16
#: lib/block_scout_web/templates/layout/_search.html.eex:34
#, elixir-autogen, elixir-format
@ -2222,6 +2346,11 @@ msgstr ""
msgid "Search tokens"
msgstr ""
#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:19
#, elixir-autogen, elixir-format
msgid "Select Yes if you want to verify Yul contract."
msgstr ""
#: lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex:19
#, elixir-autogen, elixir-format
msgid "Select yes if you want to show nightly builds."
@ -2273,11 +2402,21 @@ msgstr ""
msgid "Shows total assets held in the address"
msgstr ""
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:20
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:33
#, elixir-autogen, elixir-format
msgid "Sign in"
msgstr ""
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:24
#, elixir-autogen, elixir-format
msgid "Sign out"
msgstr ""
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:11
#, elixir-autogen, elixir-format
msgid "Signed in as "
msgstr ""
#: lib/block_scout_web/templates/block/overview.html.eex:114
#, elixir-autogen, elixir-format
msgid "Size"
@ -2344,6 +2483,11 @@ msgstr ""
msgid "Something went wrong, click to retry."
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:6
#, elixir-autogen, elixir-format
msgid "Sorry, we are unable to locate this transaction hash"
msgstr ""
#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:63
#, elixir-autogen, elixir-format
msgid "Sources *.sol files"
@ -2500,6 +2644,11 @@ msgstr ""
msgid "The total gas amount used in the block and its percentage of gas filled in the block."
msgstr ""
#: lib/block_scout_web/templates/withdrawal/index.html.eex:11
#, elixir-autogen, elixir-format
msgid "There are %{withdrawals_count} withdrawals total that withdrawn %{withdrawals_sum}"
msgstr ""
#: lib/block_scout_web/templates/address_validation/index.html.eex:16
#, elixir-autogen, elixir-format
msgid "There are no blocks validated by this address."
@ -2587,11 +2736,31 @@ msgstr ""
msgid "There are no verified contracts."
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:54
#, elixir-autogen, elixir-format
msgid "There are no withdrawals for this address."
msgstr ""
#: lib/block_scout_web/templates/block_withdrawal/index.html.eex:45
#, elixir-autogen, elixir-format
msgid "There are no withdrawals for this block."
msgstr ""
#: lib/block_scout_web/templates/withdrawal/index.html.eex:53
#, elixir-autogen, elixir-format
msgid "There are no withdrawals."
msgstr ""
#: lib/block_scout_web/templates/address_coin_balance/index.html.eex:35
#, elixir-autogen, elixir-format
msgid "There is no coin history for this address."
msgstr ""
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:29
#, elixir-autogen, elixir-format
msgid "There is no decompiled contracts for this address."
msgstr ""
#: lib/block_scout_web/templates/address_coin_balance/index.html.eex:21
#: lib/block_scout_web/templates/chain/show.html.eex:9
#, elixir-autogen, elixir-format
@ -2628,6 +2797,11 @@ msgstr ""
msgid "This is useful to allow sending requests to blockscout without having to change anything about the request."
msgstr ""
#: lib/block_scout_web/templates/page_not_found/index.html.eex:8
#, elixir-autogen, elixir-format
msgid "This page is no longer explorable! If you are lost, use the search bar to find what you are looking for."
msgstr ""
#: lib/block_scout_web/templates/transaction_state/index.html.eex:17
#, elixir-autogen, elixir-format
msgid "This transaction hasn't changed state."
@ -2811,6 +2985,11 @@ msgstr ""
msgid "Total Difficulty"
msgstr ""
#: lib/block_scout_web/templates/tokens/index.html.eex:43
#, elixir-autogen, elixir-format
msgid "Total Supply"
msgstr ""
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:84
#, elixir-autogen, elixir-format
msgid "Total Supply * Price"
@ -2864,6 +3043,11 @@ msgstr ""
msgid "Transaction %{transaction}, %{subnetwork} %{transaction}"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:205
#, elixir-autogen, elixir-format
msgid "Transaction Action"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:438
#, elixir-autogen, elixir-format
msgid "Transaction Burnt Fee"
@ -2892,7 +3076,7 @@ msgstr ""
#: lib/block_scout_web/templates/account/common/_nav.html.eex:13
#: lib/block_scout_web/templates/account/tag_transaction/index.html.eex:7
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:16
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:17
#, elixir-autogen, elixir-format
msgid "Transaction Tags"
msgstr ""
@ -3064,6 +3248,13 @@ msgstr ""
msgid "Validator Name"
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:32
#: lib/block_scout_web/templates/block_withdrawal/index.html.eex:26
#: lib/block_scout_web/templates/withdrawal/index.html.eex:26
#, elixir-autogen, elixir-format
msgid "Validator index"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:349
#, elixir-autogen, elixir-format
msgid "Value"
@ -3102,6 +3293,11 @@ msgstr ""
msgid "Verified contracts - %{subnetwork} Explorer"
msgstr ""
#: lib/block_scout_web/templates/verified_contracts/_metatags.html.eex:7
#, elixir-autogen, elixir-format
msgid "Verified contracts, %{subnetwork}, %{coin}"
msgstr ""
#: lib/block_scout_web/templates/address_contract/index.html.eex:28
#: lib/block_scout_web/templates/address_contract/index.html.eex:30
#: lib/block_scout_web/templates/address_contract/index.html.eex:198
@ -3194,6 +3390,11 @@ msgstr ""
msgid "View the account balance, transactions, and other data for %{address} on the %{network}"
msgstr ""
#: lib/block_scout_web/templates/withdrawal/_metatags.html.eex:8
#, elixir-autogen, elixir-format
msgid "View the beacon chain withdrawals on %{subnetwork}"
msgstr ""
#: lib/block_scout_web/templates/block/_metatags.html.eex:10
#, elixir-autogen, elixir-format
msgid "View the transactions, token transfers, and uncles for block number %{block_number}"
@ -3243,7 +3444,7 @@ msgstr ""
#: lib/block_scout_web/templates/account/common/_nav.html.eex:7
#: lib/block_scout_web/templates/account/watchlist/show.html.eex:7
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:14
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:15
#, elixir-autogen, elixir-format
msgid "Watch list"
msgstr ""
@ -3258,6 +3459,15 @@ msgstr ""
msgid "Wei"
msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:29
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:13
#: lib/block_scout_web/templates/block/_tabs.html.eex:13
#: lib/block_scout_web/templates/layout/_topnav.html.eex:73
#: lib/block_scout_web/templates/withdrawal/index.html.eex:5
#, elixir-autogen, elixir-format
msgid "Withdrawals"
msgstr ""
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:106
#, elixir-autogen, elixir-format
msgid "Write"
@ -3326,6 +3536,11 @@ msgstr ""
msgid "Your name*"
msgstr ""
#: lib/block_scout_web/templates/error422/index.html.eex:8
#, elixir-autogen, elixir-format
msgid "Your request contained an error, perhaps a mistyped tx/block/address hash. Try again, and check the developer tools console for more info."
msgstr ""
#: lib/block_scout_web/templates/address/overview.html.eex:111
#, elixir-autogen, elixir-format
msgid "at"
@ -3403,6 +3618,11 @@ msgstr ""
msgid "of"
msgstr ""
#: lib/block_scout_web/templates/layout/app.html.eex:97
#, elixir-autogen, elixir-format
msgid "on sign up. Didn’t receive?"
msgstr ""
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:16
#, elixir-autogen, elixir-format
msgid "page"
@ -3436,202 +3656,3 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "truffle flattener"
msgstr ""
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:29
#, elixir-autogen, elixir-format
msgid "Sign in"
msgstr ""
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:11
#, elixir-autogen, elixir-format
msgid "Signed in as "
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:8
#, elixir-autogen, elixir-format
msgid "1. If you have just submitted this transaction please wait for at least 30 seconds before refreshing this page."
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:9
#, elixir-autogen, elixir-format
msgid "2. It could still be in the TX Pool of a different node, waiting to be broadcasted."
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:10
#, elixir-autogen, elixir-format
msgid "3. During times when the network is busy (i.e during ICOs) it can take a while for your transaction to propagate through the network and for us to index it."
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:11
#, elixir-autogen, elixir-format
msgid "4. If it still does not show up after 1 hour, please check with your sender/exchange/wallet/transaction provider for additional information."
msgstr ""
#: lib/block_scout_web/templates/internal_server_error/index.html.eex:8
#, elixir-autogen, elixir-format
msgid "An unexpected error has occurred. Try reloading the page, or come back soon and try again."
msgstr ""
#: lib/block_scout_web/templates/error422/index.html.eex:9
#: lib/block_scout_web/templates/internal_server_error/index.html.eex:9
#: lib/block_scout_web/templates/page_not_found/index.html.eex:9
#: lib/block_scout_web/templates/transaction/not_found.html.eex:13
#, elixir-autogen, elixir-format
msgid "Back to home"
msgstr ""
#: lib/block_scout_web/templates/internal_server_error/index.html.eex:7
#, elixir-autogen, elixir-format
msgid "Internal server error"
msgstr ""
#: lib/block_scout_web/templates/error422/index.html.eex:7
#, elixir-autogen, elixir-format
msgid "Request cannot be processed"
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:6
#, elixir-autogen, elixir-format
msgid "Sorry, we are unable to locate this transaction hash"
msgstr ""
#: lib/block_scout_web/templates/page_not_found/index.html.eex:8
#, elixir-autogen, elixir-format
msgid "This page is no longer explorable! If you are lost, use the search bar to find what you are looking for."
msgstr ""
#: lib/block_scout_web/templates/error422/index.html.eex:8
#, elixir-autogen, elixir-format
msgid "Your request contained an error, perhaps a mistyped tx/block/address hash. Try again, and check the developer tools console for more info."
msgstr ""
#: lib/block_scout_web/templates/transaction/_actions.html.eex:101
#, elixir-autogen, elixir-format
msgid "%{qty} of <span class=\"text-muted\">Token ID [%{link_to_id}]</span>"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:204
#, elixir-autogen, elixir-format
msgid "Highlighted events of the transaction."
msgstr ""
#: lib/block_scout_web/templates/transaction/_actions.html.eex:92
#, elixir-autogen, elixir-format
msgid "Mint of %{address} <span class=\"text-muted\">To</span> %{to}"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:206
#, elixir-autogen, elixir-format
msgid "Scroll to see more"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:205
#, elixir-autogen, elixir-format
msgid "Transaction Action"
msgstr ""
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:18
#, elixir-autogen, elixir-format
msgid "Potential matches from contract method database:"
msgstr ""
#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:19
#, elixir-autogen, elixir-format
msgid "Select Yes if you want to verify Yul contract."
msgstr ""
#: lib/block_scout_web/templates/verified_contracts/_metatags.html.eex:7
#, elixir-autogen, elixir-format
msgid "Verified contracts, %{subnetwork}, %{coin}"
msgstr ""
#: lib/block_scout_web/templates/tokens/index.html.eex:38
#, elixir-autogen, elixir-format
msgid "Circulating Market Cap"
msgstr ""
#: lib/block_scout_web/templates/tokens/index.html.eex:48
#, elixir-autogen, elixir-format
msgid "Holders Count"
msgstr ""
#: lib/block_scout_web/templates/tokens/index.html.eex:43
#, elixir-autogen, elixir-format
msgid "Total Supply"
msgstr ""
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:29
#, elixir-autogen, elixir-format
msgid "There is no decompiled contracts for this address."
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:38
#: lib/block_scout_web/templates/withdrawal/index.html.eex:35
#, elixir-autogen, elixir-format
msgid "Age"
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:41
#: lib/block_scout_web/templates/block_withdrawal/index.html.eex:32
#: lib/block_scout_web/templates/withdrawal/index.html.eex:38
#, elixir-autogen, elixir-format
msgid "Amount"
msgstr ""
#: lib/block_scout_web/templates/withdrawal/_metatags.html.eex:2
#, elixir-autogen, elixir-format
msgid "Beacon chain withdrawals - %{subnetwork} Explorer"
msgstr ""
#: lib/block_scout_web/templates/withdrawal/_metatags.html.eex:7
#, elixir-autogen, elixir-format
msgid "Beacon chain, Withdrawals, %{subnetwork}, %{coin}"
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:29
#: lib/block_scout_web/templates/block_withdrawal/index.html.eex:23
#: lib/block_scout_web/templates/withdrawal/index.html.eex:23
#, elixir-autogen, elixir-format
msgid "Index"
msgstr ""
#: lib/block_scout_web/templates/withdrawal/index.html.eex:11
#, elixir-autogen, elixir-format
msgid "There are %{withdrawals_count} withdrawals total that withdrawn %{withdrawals_sum}"
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:54
#, elixir-autogen, elixir-format
msgid "There are no withdrawals for this address."
msgstr ""
#: lib/block_scout_web/templates/block_withdrawal/index.html.eex:45
#, elixir-autogen, elixir-format
msgid "There are no withdrawals for this block."
msgstr ""
#: lib/block_scout_web/templates/withdrawal/index.html.eex:53
#, elixir-autogen, elixir-format
msgid "There are no withdrawals."
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:32
#: lib/block_scout_web/templates/block_withdrawal/index.html.eex:26
#: lib/block_scout_web/templates/withdrawal/index.html.eex:26
#, elixir-autogen, elixir-format
msgid "Validator index"
msgstr ""
#: lib/block_scout_web/templates/withdrawal/_metatags.html.eex:8
#, elixir-autogen, elixir-format
msgid "View the beacon chain withdrawals on %{subnetwork}"
msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:29
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:13
#: lib/block_scout_web/templates/block/_tabs.html.eex:13
#: lib/block_scout_web/templates/layout/_topnav.html.eex:73
#: lib/block_scout_web/templates/withdrawal/index.html.eex:5
#, elixir-autogen, elixir-format
msgid "Withdrawals"
msgstr ""

@ -53,6 +53,11 @@ msgstr ""
msgid "%{count} Transactions"
msgstr ""
#: lib/block_scout_web/templates/transaction/_actions.html.eex:101
#, elixir-autogen, elixir-format
msgid "%{qty} of <span class=\"text-muted\">Token ID [%{link_to_id}]</span>"
msgstr ""
#: lib/block_scout_web/templates/chain/_metatags.html.eex:2
#, elixir-autogen, elixir-format
msgid "%{subnetwork} %{network} Explorer"
@ -86,6 +91,26 @@ msgstr ""
msgid "- We're indexing this chain right now. Some of the counts may be inaccurate."
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:8
#, elixir-autogen, elixir-format
msgid "1. If you have just submitted this transaction please wait for at least 30 seconds before refreshing this page."
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:9
#, elixir-autogen, elixir-format
msgid "2. It could still be in the TX Pool of a different node, waiting to be broadcasted."
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:10
#, elixir-autogen, elixir-format
msgid "3. During times when the network is busy (i.e during ICOs) it can take a while for your transaction to propagate through the network and for us to index it."
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:11
#, elixir-autogen, elixir-format
msgid "4. If it still does not show up after 1 hour, please check with your sender/exchange/wallet/transaction provider for additional information."
msgstr ""
#: lib/block_scout_web/templates/block/overview.html.eex:195
#, elixir-autogen, elixir-format
msgid "64-bit hash of value verifying proof-of-work (note: null for POA chains)."
@ -97,6 +122,11 @@ msgstr ""
msgid "A block producer who successfully included the block onto the blockchain."
msgstr ""
#: lib/block_scout_web/templates/layout/app.html.eex:97
#, elixir-autogen, elixir-format
msgid "A confirmation email was sent to"
msgstr ""
#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:4
#, elixir-autogen, elixir-format
msgid "A library name called in the .sol file. Multiple libraries (up to "
@ -147,7 +177,7 @@ msgstr ""
#: lib/block_scout_web/templates/account/api_key/index.html.eex:7
#: lib/block_scout_web/templates/account/common/_nav.html.eex:16
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:17
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:18
#, elixir-autogen, elixir-format
msgid "API keys"
msgstr ""
@ -252,7 +282,7 @@ msgstr ""
#: lib/block_scout_web/templates/account/common/_nav.html.eex:10
#: lib/block_scout_web/templates/account/tag_address/index.html.eex:7
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:15
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:16
#, elixir-autogen, elixir-format
msgid "Address Tags"
msgstr ""
@ -282,6 +312,12 @@ msgstr ""
msgid "Addresses"
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:38
#: lib/block_scout_web/templates/withdrawal/index.html.eex:35
#, elixir-autogen, elixir-format
msgid "Age"
msgstr ""
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:26
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:28
#: lib/block_scout_web/templates/address_transaction/index.html.eex:22
@ -310,6 +346,13 @@ msgstr ""
msgid "All tokens in the account and total value."
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:41
#: lib/block_scout_web/templates/block_withdrawal/index.html.eex:32
#: lib/block_scout_web/templates/withdrawal/index.html.eex:38
#, elixir-autogen, elixir-format
msgid "Amount"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:437
#, elixir-autogen, elixir-format
msgid "Amount of"
@ -320,6 +363,11 @@ msgstr ""
msgid "Amount of distributed reward. Miners receive a static block reward + Tx fees + uncle fees."
msgstr ""
#: lib/block_scout_web/templates/internal_server_error/index.html.eex:8
#, elixir-autogen, elixir-format
msgid "An unexpected error has occurred. Try reloading the page, or come back soon and try again."
msgstr ""
#: lib/block_scout_web/templates/api_docs/eth_rpc.html.eex:15
#, elixir-autogen, elixir-format
msgid "Anything not in this list is not supported. Click on the method to be taken to the documentation for that method, and check the notes section for any potential differences."
@ -365,6 +413,14 @@ msgstr ""
msgid "Back to Watch list (Cancel)"
msgstr ""
#: lib/block_scout_web/templates/error422/index.html.eex:9
#: lib/block_scout_web/templates/internal_server_error/index.html.eex:9
#: lib/block_scout_web/templates/page_not_found/index.html.eex:9
#: lib/block_scout_web/templates/transaction/not_found.html.eex:13
#, elixir-autogen, elixir-format
msgid "Back to home"
msgstr ""
#: lib/block_scout_web/templates/account/watchlist/show.html.eex:24
#: lib/block_scout_web/templates/address/overview.html.eex:150
#: lib/block_scout_web/templates/address_token/overview.html.eex:51
@ -399,6 +455,16 @@ msgstr ""
msgid "Base URL:"
msgstr ""
#: lib/block_scout_web/templates/withdrawal/_metatags.html.eex:2
#, elixir-autogen, elixir-format
msgid "Beacon chain withdrawals - %{subnetwork} Explorer"
msgstr ""
#: lib/block_scout_web/templates/withdrawal/_metatags.html.eex:7
#, elixir-autogen, elixir-format
msgid "Beacon chain, Withdrawals, %{subnetwork}, %{coin}"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:472
#, elixir-autogen, elixir-format
msgid "Binary data included with the transaction. See input / logs below for additional info."
@ -565,6 +631,11 @@ msgstr ""
msgid "Chore Reward"
msgstr ""
#: lib/block_scout_web/templates/tokens/index.html.eex:38
#, elixir-autogen, elixir-format
msgid "Circulating Market Cap"
msgstr ""
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:137
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:106
#, elixir-autogen, elixir-format
@ -962,7 +1033,7 @@ msgstr ""
#: lib/block_scout_web/templates/account/common/_nav.html.eex:19
#: lib/block_scout_web/templates/account/custom_abi/form.html.eex:8
#: lib/block_scout_web/templates/account/custom_abi/index.html.eex:7
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:18
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:19
#, elixir-autogen, elixir-format
msgid "Custom ABI"
msgstr ""
@ -1429,11 +1500,21 @@ msgstr ""
msgid "Hex (Default)"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:204
#, elixir-autogen, elixir-format
msgid "Highlighted events of the transaction."
msgstr ""
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:108
#, elixir-autogen, elixir-format
msgid "Holders"
msgstr ""
#: lib/block_scout_web/templates/tokens/index.html.eex:48
#, elixir-autogen, elixir-format
msgid "Holders Count"
msgstr ""
#: lib/block_scout_web/templates/api_docs/eth_rpc.html.eex:11
#, elixir-autogen, elixir-format
msgid "However, in general, the"
@ -1478,6 +1559,13 @@ msgstr ""
msgid "Incoming"
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:29
#: lib/block_scout_web/templates/block_withdrawal/index.html.eex:23
#: lib/block_scout_web/templates/withdrawal/index.html.eex:23
#, elixir-autogen, elixir-format
msgid "Index"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:464
#, elixir-autogen, elixir-format
msgid "Index position of Transaction in the block."
@ -1518,6 +1606,11 @@ msgstr ""
msgid "Internal Transactions"
msgstr ""
#: lib/block_scout_web/templates/internal_server_error/index.html.eex:7
#, elixir-autogen, elixir-format
msgid "Internal server error"
msgstr ""
#: lib/block_scout_web/templates/tokens/inventory/index.html.eex:16
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:19
#: lib/block_scout_web/views/tokens/overview_view.ex:42
@ -1709,6 +1802,11 @@ msgstr ""
msgid "Minimum fee required per unit of gas. Fee adjusts based on network congestion."
msgstr ""
#: lib/block_scout_web/templates/transaction/_actions.html.eex:92
#, elixir-autogen, elixir-format
msgid "Mint of %{address} <span class=\"text-muted\">To</span> %{to}"
msgstr ""
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:223
#, elixir-autogen, elixir-format
msgid "Model"
@ -1984,6 +2082,12 @@ msgstr ""
msgid "Play"
msgstr ""
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:22
#: lib/block_scout_web/templates/layout/app.html.eex:97
#, elixir-autogen, elixir-format
msgid "Please confirm your email address to use the My Account feature."
msgstr ""
#: lib/block_scout_web/templates/account/watchlist_address/form.html.eex:68
#, elixir-autogen, elixir-format
msgid "Please select notification methods:"
@ -2004,6 +2108,11 @@ msgstr ""
msgid "Position %{index}"
msgstr ""
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:18
#, elixir-autogen, elixir-format
msgid "Potential matches from contract method database:"
msgstr ""
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:32
#, elixir-autogen, elixir-format
msgid "Potential matches from our contract method database:"
@ -2043,12 +2152,12 @@ msgid "Priority Fees"
msgstr ""
#: lib/block_scout_web/templates/account/common/_nav.html.eex:4
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:13
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:14
#, elixir-autogen, elixir-format
msgid "Profile"
msgstr ""
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:19
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:20
#, elixir-autogen, elixir-format
msgid "Public Tags"
msgstr ""
@ -2139,6 +2248,11 @@ msgstr ""
msgid "Request a public tag/label"
msgstr ""
#: lib/block_scout_web/templates/error422/index.html.eex:7
#, elixir-autogen, elixir-format
msgid "Request cannot be processed"
msgstr ""
#: lib/block_scout_web/templates/account/public_tags_request/index.html.eex:37
#, elixir-autogen, elixir-format
msgid "Request to add public tag"
@ -2149,6 +2263,11 @@ msgstr ""
msgid "Request to edit a public tag/label"
msgstr ""
#: lib/block_scout_web/templates/layout/app.html.eex:97
#, elixir-autogen, elixir-format
msgid "Resend verification email"
msgstr ""
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:112
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:38
#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:104
@ -2201,6 +2320,11 @@ msgstr ""
msgid "Save"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:206
#, elixir-autogen, elixir-format
msgid "Scroll to see more"
msgstr ""
#: lib/block_scout_web/templates/address_logs/index.html.eex:16
#: lib/block_scout_web/templates/layout/_search.html.eex:34
#, elixir-autogen, elixir-format
@ -2222,6 +2346,11 @@ msgstr ""
msgid "Search tokens"
msgstr ""
#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:19
#, elixir-autogen, elixir-format
msgid "Select Yes if you want to verify Yul contract."
msgstr ""
#: lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex:19
#, elixir-autogen, elixir-format
msgid "Select yes if you want to show nightly builds."
@ -2273,11 +2402,21 @@ msgstr ""
msgid "Shows total assets held in the address"
msgstr ""
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:20
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:33
#, elixir-autogen, elixir-format
msgid "Sign in"
msgstr ""
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:24
#, elixir-autogen, elixir-format
msgid "Sign out"
msgstr ""
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:11
#, elixir-autogen, elixir-format
msgid "Signed in as "
msgstr ""
#: lib/block_scout_web/templates/block/overview.html.eex:114
#, elixir-autogen, elixir-format
msgid "Size"
@ -2344,6 +2483,11 @@ msgstr ""
msgid "Something went wrong, click to retry."
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:6
#, elixir-autogen, elixir-format
msgid "Sorry, we are unable to locate this transaction hash"
msgstr ""
#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:63
#, elixir-autogen, elixir-format
msgid "Sources *.sol files"
@ -2500,6 +2644,11 @@ msgstr ""
msgid "The total gas amount used in the block and its percentage of gas filled in the block."
msgstr ""
#: lib/block_scout_web/templates/withdrawal/index.html.eex:11
#, elixir-autogen, elixir-format
msgid "There are %{withdrawals_count} withdrawals total that withdrawn %{withdrawals_sum}"
msgstr ""
#: lib/block_scout_web/templates/address_validation/index.html.eex:16
#, elixir-autogen, elixir-format
msgid "There are no blocks validated by this address."
@ -2587,11 +2736,31 @@ msgstr ""
msgid "There are no verified contracts."
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:54
#, elixir-autogen, elixir-format
msgid "There are no withdrawals for this address."
msgstr ""
#: lib/block_scout_web/templates/block_withdrawal/index.html.eex:45
#, elixir-autogen, elixir-format
msgid "There are no withdrawals for this block."
msgstr ""
#: lib/block_scout_web/templates/withdrawal/index.html.eex:53
#, elixir-autogen, elixir-format
msgid "There are no withdrawals."
msgstr ""
#: lib/block_scout_web/templates/address_coin_balance/index.html.eex:35
#, elixir-autogen, elixir-format
msgid "There is no coin history for this address."
msgstr ""
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:29
#, elixir-autogen, elixir-format
msgid "There is no decompiled contracts for this address."
msgstr ""
#: lib/block_scout_web/templates/address_coin_balance/index.html.eex:21
#: lib/block_scout_web/templates/chain/show.html.eex:9
#, elixir-autogen, elixir-format
@ -2628,6 +2797,11 @@ msgstr ""
msgid "This is useful to allow sending requests to blockscout without having to change anything about the request."
msgstr ""
#: lib/block_scout_web/templates/page_not_found/index.html.eex:8
#, elixir-autogen, elixir-format
msgid "This page is no longer explorable! If you are lost, use the search bar to find what you are looking for."
msgstr ""
#: lib/block_scout_web/templates/transaction_state/index.html.eex:17
#, elixir-autogen, elixir-format
msgid "This transaction hasn't changed state."
@ -2811,6 +2985,11 @@ msgstr ""
msgid "Total Difficulty"
msgstr ""
#: lib/block_scout_web/templates/tokens/index.html.eex:43
#, elixir-autogen, elixir-format
msgid "Total Supply"
msgstr ""
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:84
#, elixir-autogen, elixir-format
msgid "Total Supply * Price"
@ -2864,6 +3043,11 @@ msgstr ""
msgid "Transaction %{transaction}, %{subnetwork} %{transaction}"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:205
#, elixir-autogen, elixir-format
msgid "Transaction Action"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:438
#, elixir-autogen, elixir-format
msgid "Transaction Burnt Fee"
@ -2892,7 +3076,7 @@ msgstr ""
#: lib/block_scout_web/templates/account/common/_nav.html.eex:13
#: lib/block_scout_web/templates/account/tag_transaction/index.html.eex:7
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:16
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:17
#, elixir-autogen, elixir-format
msgid "Transaction Tags"
msgstr ""
@ -3064,6 +3248,13 @@ msgstr ""
msgid "Validator Name"
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:32
#: lib/block_scout_web/templates/block_withdrawal/index.html.eex:26
#: lib/block_scout_web/templates/withdrawal/index.html.eex:26
#, elixir-autogen, elixir-format
msgid "Validator index"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:349
#, elixir-autogen, elixir-format
msgid "Value"
@ -3102,6 +3293,11 @@ msgstr ""
msgid "Verified contracts - %{subnetwork} Explorer"
msgstr ""
#: lib/block_scout_web/templates/verified_contracts/_metatags.html.eex:7
#, elixir-autogen, elixir-format
msgid "Verified contracts, %{subnetwork}, %{coin}"
msgstr ""
#: lib/block_scout_web/templates/address_contract/index.html.eex:28
#: lib/block_scout_web/templates/address_contract/index.html.eex:30
#: lib/block_scout_web/templates/address_contract/index.html.eex:198
@ -3194,6 +3390,11 @@ msgstr ""
msgid "View the account balance, transactions, and other data for %{address} on the %{network}"
msgstr ""
#: lib/block_scout_web/templates/withdrawal/_metatags.html.eex:8
#, elixir-autogen, elixir-format
msgid "View the beacon chain withdrawals on %{subnetwork}"
msgstr ""
#: lib/block_scout_web/templates/block/_metatags.html.eex:10
#, elixir-autogen, elixir-format
msgid "View the transactions, token transfers, and uncles for block number %{block_number}"
@ -3243,7 +3444,7 @@ msgstr ""
#: lib/block_scout_web/templates/account/common/_nav.html.eex:7
#: lib/block_scout_web/templates/account/watchlist/show.html.eex:7
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:14
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:15
#, elixir-autogen, elixir-format
msgid "Watch list"
msgstr ""
@ -3258,6 +3459,15 @@ msgstr ""
msgid "Wei"
msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:29
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:13
#: lib/block_scout_web/templates/block/_tabs.html.eex:13
#: lib/block_scout_web/templates/layout/_topnav.html.eex:73
#: lib/block_scout_web/templates/withdrawal/index.html.eex:5
#, elixir-autogen, elixir-format
msgid "Withdrawals"
msgstr ""
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:106
#, elixir-autogen, elixir-format
msgid "Write"
@ -3326,6 +3536,11 @@ msgstr ""
msgid "Your name*"
msgstr ""
#: lib/block_scout_web/templates/error422/index.html.eex:8
#, elixir-autogen, elixir-format
msgid "Your request contained an error, perhaps a mistyped tx/block/address hash. Try again, and check the developer tools console for more info."
msgstr ""
#: lib/block_scout_web/templates/address/overview.html.eex:111
#, elixir-autogen, elixir-format
msgid "at"
@ -3403,6 +3618,11 @@ msgstr ""
msgid "of"
msgstr ""
#: lib/block_scout_web/templates/layout/app.html.eex:97
#, elixir-autogen, elixir-format
msgid "on sign up. Didn’t receive?"
msgstr ""
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:16
#, elixir-autogen, elixir-format
msgid "page"
@ -3436,202 +3656,3 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "truffle flattener"
msgstr ""
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:29
#, elixir-autogen, elixir-format
msgid "Sign in"
msgstr ""
#: lib/block_scout_web/templates/layout/_account_menu_item.html.eex:11
#, elixir-autogen, elixir-format
msgid "Signed in as "
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:8
#, elixir-autogen, elixir-format, fuzzy
msgid "1. If you have just submitted this transaction please wait for at least 30 seconds before refreshing this page."
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:9
#, elixir-autogen, elixir-format, fuzzy
msgid "2. It could still be in the TX Pool of a different node, waiting to be broadcasted."
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:10
#, elixir-autogen, elixir-format, fuzzy
msgid "3. During times when the network is busy (i.e during ICOs) it can take a while for your transaction to propagate through the network and for us to index it."
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:11
#, elixir-autogen, elixir-format, fuzzy
msgid "4. If it still does not show up after 1 hour, please check with your sender/exchange/wallet/transaction provider for additional information."
msgstr ""
#: lib/block_scout_web/templates/internal_server_error/index.html.eex:8
#, elixir-autogen, elixir-format
msgid "An unexpected error has occurred. Try reloading the page, or come back soon and try again."
msgstr ""
#: lib/block_scout_web/templates/error422/index.html.eex:9
#: lib/block_scout_web/templates/internal_server_error/index.html.eex:9
#: lib/block_scout_web/templates/page_not_found/index.html.eex:9
#: lib/block_scout_web/templates/transaction/not_found.html.eex:13
#, elixir-autogen, elixir-format, fuzzy
msgid "Back to home"
msgstr ""
#: lib/block_scout_web/templates/internal_server_error/index.html.eex:7
#, elixir-autogen, elixir-format
msgid "Internal server error"
msgstr ""
#: lib/block_scout_web/templates/error422/index.html.eex:7
#, elixir-autogen, elixir-format
msgid "Request cannot be processed"
msgstr ""
#: lib/block_scout_web/templates/transaction/not_found.html.eex:6
#, elixir-autogen, elixir-format, fuzzy
msgid "Sorry, we are unable to locate this transaction hash"
msgstr ""
#: lib/block_scout_web/templates/page_not_found/index.html.eex:8
#, elixir-autogen, elixir-format
msgid "This page is no longer explorable! If you are lost, use the search bar to find what you are looking for."
msgstr ""
#: lib/block_scout_web/templates/error422/index.html.eex:8
#, elixir-autogen, elixir-format
msgid "Your request contained an error, perhaps a mistyped tx/block/address hash. Try again, and check the developer tools console for more info."
msgstr ""
#: lib/block_scout_web/templates/transaction/_actions.html.eex:101
#, elixir-autogen, elixir-format
msgid "%{qty} of <span class=\"text-muted\">Token ID [%{link_to_id}]</span>"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:204
#, elixir-autogen, elixir-format
msgid "Highlighted events of the transaction."
msgstr ""
#: lib/block_scout_web/templates/transaction/_actions.html.eex:92
#, elixir-autogen, elixir-format
msgid "Mint of %{address} <span class=\"text-muted\">To</span> %{to}"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:206
#, elixir-autogen, elixir-format
msgid "Scroll to see more"
msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:205
#, elixir-autogen, elixir-format, fuzzy
msgid "Transaction Action"
msgstr ""
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:18
#, elixir-autogen, elixir-format, fuzzy
msgid "Potential matches from contract method database:"
msgstr ""
#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:19
#, elixir-autogen, elixir-format, fuzzy
msgid "Select Yes if you want to verify Yul contract."
msgstr ""
#: lib/block_scout_web/templates/verified_contracts/_metatags.html.eex:7
#, elixir-autogen, elixir-format, fuzzy
msgid "Verified contracts, %{subnetwork}, %{coin}"
msgstr ""
#: lib/block_scout_web/templates/tokens/index.html.eex:38
#, elixir-autogen, elixir-format
msgid "Circulating Market Cap"
msgstr ""
#: lib/block_scout_web/templates/tokens/index.html.eex:48
#, elixir-autogen, elixir-format, fuzzy
msgid "Holders Count"
msgstr ""
#: lib/block_scout_web/templates/tokens/index.html.eex:43
#, elixir-autogen, elixir-format, fuzzy
msgid "Total Supply"
msgstr ""
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:29
#, elixir-autogen, elixir-format
msgid "There is no decompiled contracts for this address."
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:38
#: lib/block_scout_web/templates/withdrawal/index.html.eex:35
#, elixir-autogen, elixir-format
msgid "Age"
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:41
#: lib/block_scout_web/templates/block_withdrawal/index.html.eex:32
#: lib/block_scout_web/templates/withdrawal/index.html.eex:38
#, elixir-autogen, elixir-format, fuzzy
msgid "Amount"
msgstr ""
#: lib/block_scout_web/templates/withdrawal/_metatags.html.eex:2
#, elixir-autogen, elixir-format
msgid "Beacon chain withdrawals - %{subnetwork} Explorer"
msgstr ""
#: lib/block_scout_web/templates/withdrawal/_metatags.html.eex:7
#, elixir-autogen, elixir-format
msgid "Beacon chain, Withdrawals, %{subnetwork}, %{coin}"
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:29
#: lib/block_scout_web/templates/block_withdrawal/index.html.eex:23
#: lib/block_scout_web/templates/withdrawal/index.html.eex:23
#, elixir-autogen, elixir-format, fuzzy
msgid "Index"
msgstr ""
#: lib/block_scout_web/templates/withdrawal/index.html.eex:11
#, elixir-autogen, elixir-format
msgid "There are %{withdrawals_count} withdrawals total that withdrawn %{withdrawals_sum}"
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:54
#, elixir-autogen, elixir-format, fuzzy
msgid "There are no withdrawals for this address."
msgstr ""
#: lib/block_scout_web/templates/block_withdrawal/index.html.eex:45
#, elixir-autogen, elixir-format, fuzzy
msgid "There are no withdrawals for this block."
msgstr ""
#: lib/block_scout_web/templates/withdrawal/index.html.eex:53
#, elixir-autogen, elixir-format, fuzzy
msgid "There are no withdrawals."
msgstr ""
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:32
#: lib/block_scout_web/templates/block_withdrawal/index.html.eex:26
#: lib/block_scout_web/templates/withdrawal/index.html.eex:26
#, elixir-autogen, elixir-format, fuzzy
msgid "Validator index"
msgstr ""
#: lib/block_scout_web/templates/withdrawal/_metatags.html.eex:8
#, elixir-autogen, elixir-format, fuzzy
msgid "View the beacon chain withdrawals on %{subnetwork}"
msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:29
#: lib/block_scout_web/templates/address_withdrawal/index.html.eex:13
#: lib/block_scout_web/templates/block/_tabs.html.eex:13
#: lib/block_scout_web/templates/layout/_topnav.html.eex:73
#: lib/block_scout_web/templates/withdrawal/index.html.eex:5
#, elixir-autogen, elixir-format
msgid "Withdrawals"
msgstr ""

@ -17,6 +17,7 @@ defmodule Explorer.Account.Identity do
field(:name, Explorer.Encrypted.Binary)
field(:nickname, Explorer.Encrypted.Binary)
field(:avatar, Explorer.Encrypted.Binary)
field(:verification_email_sent_at, :utc_datetime_usec)
has_many(:tag_addresses, TagAddress)
has_many(:watchlists, Watchlist)
@ -29,7 +30,7 @@ defmodule Explorer.Account.Identity do
@doc false
def changeset(identity, attrs) do
identity
|> cast(attrs, [:uid, :email, :name, :nickname, :avatar])
|> cast(attrs, [:uid, :email, :name, :nickname, :avatar, :verification_email_sent_at])
|> validate_required([:uid, :email, :name])
|> put_hashed_fields()
end

@ -0,0 +1,48 @@
defmodule Explorer.ThirdPartyIntegrations.Auth0 do
@moduledoc """
Module for fetching jwt auth0 Management API (https://auth0.com/docs/api/management/v2) jwt
"""
@redis_key "auth0"
@doc """
Function responsible for retrieving machine to machine JWT for interacting with Auth0 Management API.
Firstly it tries to access cached token and if there is no cached one, token will be requested from Auth0
"""
@spec get_m2m_jwt() :: nil | String.t()
def get_m2m_jwt, do: get_m2m_jwt_inner(Redix.command(:redix, ["GET", @redis_key]))
def get_m2m_jwt_inner({:ok, token}) when not is_nil(token), do: token
def get_m2m_jwt_inner(_) do
config = Application.get_env(:ueberauth, Ueberauth.Strategy.Auth0.OAuth)
body = %{
"client_id" => config[:client_id],
"client_secret" => config[:client_secret],
"audience" => "https://#{config[:domain]}/api/v2/",
"grant_type" => "client_credentials"
}
headers = [{"Content-type", "application/json"}]
case HTTPoison.post("https://#{config[:domain]}/oauth/token", Jason.encode!(body), headers, []) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
case Jason.decode!(body) do
%{"access_token" => token, "expires_in" => ttl} ->
cache_token(token, ttl - 1)
_ ->
nil
end
_ ->
nil
end
end
defp cache_token(token, ttl) do
chain_id = Application.get_env(:block_scout_web, :chain_id)
Redix.command(:redix, ["SET", "#{chain_id}_#{@redis_key}", token, "EX", ttl])
token
end
end

@ -0,0 +1,9 @@
defmodule Explorer.Repo.Account.Migrations.AddVerificationEmailSentAt do
use Ecto.Migration
def change do
alter table(:account_identities) do
add(:verification_email_sent_at, :"timestamp without time zone", null: true)
end
end
end

@ -356,7 +356,8 @@ config :explorer, Explorer.Account,
sendgrid: [
sender: System.get_env("ACCOUNT_SENDGRID_SENDER"),
template: System.get_env("ACCOUNT_SENDGRID_TEMPLATE")
]
],
resend_interval: ConfigHelper.parse_time_env_var("ACCOUNT_VERIFICATION_EMAIL_RESEND_INTERVAL", "5m")
config :explorer, :token_id_migration,
first_block: ConfigHelper.parse_integer_env_var("TOKEN_ID_MIGRATION_FIRST_BLOCK", 0),

@ -201,3 +201,4 @@ ACCOUNT_REDIS_URL=redis://redis_db:6379
# AMPLITUDE_URL=
EIP_1559_ELASTICITY_MULTIPLIER=2
# API_SENSITIVE_ENDPOINTS_KEY=
# ACCOUNT_VERIFICATION_EMAIL_RESEND_INTERVAL=

@ -701,6 +701,9 @@ endif
ifdef API_SENSITIVE_ENDPOINTS_KEY
BLOCKSCOUT_CONTAINER_PARAMS += -e 'API_SENSITIVE_ENDPOINTS_KEY=$(API_SENSITIVE_ENDPOINTS_KEY)'
endif
ifdef ACCOUNT_VERIFICATION_EMAIL_RESEND_INTERVAL
BLOCKSCOUT_CONTAINER_PARAMS += -e 'ACCOUNT_VERIFICATION_EMAIL_RESEND_INTERVAL=$(ACCOUNT_VERIFICATION_EMAIL_RESEND_INTERVAL)'
endif
HAS_BLOCKSCOUT_IMAGE := $(shell docker images | grep -sw "${BS_CONTAINER_IMAGE} ")
build:

Loading…
Cancel
Save