From ce9d67a7d000b76d84e11f724033eb006cf0c7a4 Mon Sep 17 00:00:00 2001
From: nikitosing <32202610+nikitosing@users.noreply.github.com>
Date: Tue, 9 May 2023 11:30:07 +0300
Subject: [PATCH] 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
---
CHANGELOG.md | 1 +
.../block_scout_web/assets/css/main-page.scss | 6 +
apps/block_scout_web/assets/js/lib/modals.js | 9 +-
.../assets/js/lib/public_tags_request_form.js | 1 -
apps/block_scout_web/assets/js/pages/chain.js | 24 +
.../lib/block_scout_web/api_router.ex | 6 +-
.../account/api/v1/authenticate_controller.ex | 2 +-
.../account/api/v1/email_controller.ex | 64 +++
.../account/api/v1/fallback_controller.ex | 20 +-
.../account/api/v1/tags_controller.ex | 4 +-
.../account/api/v1/user_controller.ex | 50 +-
.../controllers/account/auth_controller.ex | 12 +-
.../block_scout_web/models/user_from_auth.ex | 39 +-
.../layout/_account_menu_item.html.eex | 66 +--
.../templates/layout/app.html.eex | 12 +-
apps/block_scout_web/priv/gettext/default.pot | 435 +++++++++---------
.../priv/gettext/en/LC_MESSAGES/default.po | 435 +++++++++---------
.../explorer/lib/explorer/account/identity.ex | 3 +-
.../third_party_integrations/auth0.ex | 48 ++
...2083519_add_verification_email_sent_at.exs | 9 +
config/runtime.exs | 3 +-
docker-compose/envs/common-blockscout.env | 1 +
docker/Makefile | 3 +
23 files changed, 750 insertions(+), 503 deletions(-)
create mode 100644 apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/email_controller.ex
create mode 100644 apps/explorer/lib/explorer/third_party_integrations/auth0.ex
create mode 100644 apps/explorer/priv/account/migrations/20230502083519_add_verification_email_sent_at.exs
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9fe38ef08b..89bbf472d1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
diff --git a/apps/block_scout_web/assets/css/main-page.scss b/apps/block_scout_web/assets/css/main-page.scss
index 690d78b7e6..7aeb2d2cea 100644
--- a/apps/block_scout_web/assets/css/main-page.scss
+++ b/apps/block_scout_web/assets/css/main-page.scss
@@ -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";
diff --git a/apps/block_scout_web/assets/js/lib/modals.js b/apps/block_scout_web/assets/js/lib/modals.js
index 3c862ea4a9..ec0f83771d 100644
--- a/apps/block_scout_web/assets/js/lib/modals.js
+++ b/apps/block_scout_web/assets/js/lib/modals.js
@@ -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') {
diff --git a/apps/block_scout_web/assets/js/lib/public_tags_request_form.js b/apps/block_scout_web/assets/js/lib/public_tags_request_form.js
index f2794f6918..df59c68cb0 100644
--- a/apps/block_scout_web/assets/js/lib/public_tags_request_form.js
+++ b/apps/block_scout_web/assets/js/lib/public_tags_request_form.js
@@ -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)
diff --git a/apps/block_scout_web/assets/js/pages/chain.js b/apps/block_scout_web/assets/js/pages/chain.js
index c71eb6b575..858a04b6c1 100644
--- a/apps/block_scout_web/assets/js/pages/chain.js
+++ b/apps/block_scout_web/assets/js/pages/chain.js
@@ -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')
+ })
+}
+)
diff --git a/apps/block_scout_web/lib/block_scout_web/api_router.ex b/apps/block_scout_web/lib/block_scout_web/api_router.ex
index e1325432fb..0a738baf3f 100644
--- a/apps/block_scout_web/lib/block_scout_web/api_router.ex
+++ b/apps/block_scout_web/lib/block_scout_web/api_router.ex
@@ -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)
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/authenticate_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/authenticate_controller.ex
index 386d082fbc..0c16034d02 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/authenticate_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/authenticate_controller.ex
@@ -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)
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/email_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/email_controller.ex
new file mode 100644
index 0000000000..b8f2ce7631
--- /dev/null
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/email_controller.ex
@@ -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
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/fallback_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/fallback_controller.ex
index 1e7a02bc55..6c6603b53f 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/fallback_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/fallback_controller.ex
@@ -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
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/tags_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/tags_controller.ex
index 7c40a29e6b..3549024f90 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/tags_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/tags_controller.ex
@@ -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
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/user_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/user_controller.ex
index 837d64771d..42b67c7c17 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/user_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/user_controller.ex
@@ -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(%{
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/account/auth_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/account/auth_controller.ex
index c97ab5fb3a..6d6c926c2c 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/account/auth_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/account/auth_controller.ex
@@ -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
diff --git a/apps/block_scout_web/lib/block_scout_web/models/user_from_auth.ex b/apps/block_scout_web/lib/block_scout_web/models/user_from_auth.ex
index 058b160540..71cdef5103 100644
--- a/apps/block_scout_web/lib/block_scout_web/models/user_from_auth.ex
+++ b/apps/block_scout_web/lib/block_scout_web/models/user_from_auth.ex
@@ -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
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/layout/_account_menu_item.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/layout/_account_menu_item.html.eex
index 541dcecb45..e7742d231f 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/layout/_account_menu_item.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/layout/_account_menu_item.html.eex
@@ -1,33 +1,37 @@
<%= if Explorer.Account.enabled?() do %>
- <%= if @current_user do %>
-
-
-
-
-
-
-
-
- <% else %>
-
-
-
- <%= render BlockScoutWeb.IconsView, "_accounts_icon.html" %>
-
- <%= gettext "Sign in" %>
-
-
- <% end %>
+ <%= if @current_user do %>
+
+
+
+
+
+
+
+
+ <% else %>
+
+
+
+ <%= render BlockScoutWeb.IconsView, "_accounts_icon.html" %>
+
+ <%= gettext "Sign in" %>
+
+
+ <% end %>
<% end %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex
index 8f2310b37c..0762d44d33 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex
@@ -91,11 +91,15 @@
<% end %>
<% end %>
- <%= render BlockScoutWeb.LayoutView, "_topnav.html", current_user: Conn.get_session(@conn, :current_user), conn: @conn %>
-
-
+ <% 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 %>
+ <%= gettext("Please confirm your email address to use the My Account feature.") %> <%= gettext("A confirmation email was sent to") %> <%=session[:email] %> <%= gettext "on sign up. Didn’t receive?" %> <%= gettext "Resend verification email" %>.
+ <% else %>
<%= get_flash(@conn, :info) %>
- <%= get_flash(@conn, :error) %>
+ <% end %>
+ <%= get_flash(@conn, :error) %>
+
<%= @inner_content %>
<%= render BlockScoutWeb.LayoutView, "_footer.html", assigns %>
diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot
index 6a556a3a59..759f5dd799 100644
--- a/apps/block_scout_web/priv/gettext/default.pot
+++ b/apps/block_scout_web/priv/gettext/default.pot
@@ -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 Token ID [%{link_to_id}]"
+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} To %{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 Token ID [%{link_to_id}]"
-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} To %{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 ""
diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
index ea8c96ba25..759f5dd799 100644
--- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
+++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
@@ -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 Token ID [%{link_to_id}]"
+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} To %{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 Token ID [%{link_to_id}]"
-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} To %{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 ""
diff --git a/apps/explorer/lib/explorer/account/identity.ex b/apps/explorer/lib/explorer/account/identity.ex
index d0766d7d35..05171bc9f7 100644
--- a/apps/explorer/lib/explorer/account/identity.ex
+++ b/apps/explorer/lib/explorer/account/identity.ex
@@ -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
diff --git a/apps/explorer/lib/explorer/third_party_integrations/auth0.ex b/apps/explorer/lib/explorer/third_party_integrations/auth0.ex
new file mode 100644
index 0000000000..4afad8845f
--- /dev/null
+++ b/apps/explorer/lib/explorer/third_party_integrations/auth0.ex
@@ -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
diff --git a/apps/explorer/priv/account/migrations/20230502083519_add_verification_email_sent_at.exs b/apps/explorer/priv/account/migrations/20230502083519_add_verification_email_sent_at.exs
new file mode 100644
index 0000000000..a3145bab49
--- /dev/null
+++ b/apps/explorer/priv/account/migrations/20230502083519_add_verification_email_sent_at.exs
@@ -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
diff --git a/config/runtime.exs b/config/runtime.exs
index 216e45857f..b949b4b410 100644
--- a/config/runtime.exs
+++ b/config/runtime.exs
@@ -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),
diff --git a/docker-compose/envs/common-blockscout.env b/docker-compose/envs/common-blockscout.env
index bd23653152..eeba9bbf77 100644
--- a/docker-compose/envs/common-blockscout.env
+++ b/docker-compose/envs/common-blockscout.env
@@ -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=
diff --git a/docker/Makefile b/docker/Makefile
index b10f12ebfe..2b1826af45 100644
--- a/docker/Makefile
+++ b/docker/Makefile
@@ -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: