Explorer redesign part 4
This commit is contained in:
parent
12ca86c601
commit
03f72f07f2
262
server/public.go
262
server/public.go
@ -5,10 +5,11 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
@ -239,12 +240,12 @@ func (s *PublicServer) OnNewTx(tx *bchain.MempoolTx) {
|
||||
}
|
||||
|
||||
func (s *PublicServer) txRedirect(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, joinURL(s.explorerURL, r.URL.Path), 302)
|
||||
http.Redirect(w, r, joinURL(s.explorerURL, r.URL.Path), http.StatusFound)
|
||||
s.metrics.ExplorerViews.With(common.Labels{"action": "tx-redirect"}).Inc()
|
||||
}
|
||||
|
||||
func (s *PublicServer) addressRedirect(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, joinURL(s.explorerURL, r.URL.Path), 302)
|
||||
http.Redirect(w, r, joinURL(s.explorerURL, r.URL.Path), http.StatusFound)
|
||||
s.metrics.ExplorerViews.With(common.Labels{"action": "address-redirect"}).Inc()
|
||||
}
|
||||
|
||||
@ -371,6 +372,7 @@ func (s *PublicServer) newTemplateData(r *http.Request) *TemplateData {
|
||||
if ticker != nil {
|
||||
t.SecondaryCoin = strings.ToUpper(secondary)
|
||||
t.CurrentSecondaryCoinRate = float64(ticker.Rates[secondary])
|
||||
t.CurrentTicker = ticker
|
||||
t.UseSecondaryCoin, _ = strconv.ParseBool(r.URL.Query().Get("use_secondary"))
|
||||
if !t.UseSecondaryCoin {
|
||||
t.UseSecondaryCoin = cookieUseSecondary
|
||||
@ -470,49 +472,55 @@ const (
|
||||
|
||||
// TemplateData is used to transfer data to the templates
|
||||
type TemplateData struct {
|
||||
CoinName string
|
||||
CoinShortcut string
|
||||
CoinLabel string
|
||||
InternalExplorer bool
|
||||
ChainType bchain.ChainType
|
||||
Address *api.Address
|
||||
AddrStr string
|
||||
Tx *api.Tx
|
||||
Error *api.APIError
|
||||
Blocks *api.Blocks
|
||||
Block *api.Block
|
||||
Info *api.SystemInfo
|
||||
MempoolTxids *api.MempoolTxids
|
||||
Page int
|
||||
PrevPage int
|
||||
NextPage int
|
||||
PagingRange []int
|
||||
PageParams template.URL
|
||||
TOSLink string
|
||||
SendTxHex string
|
||||
Status string
|
||||
NonZeroBalanceTokens bool
|
||||
TokenId string
|
||||
URI string
|
||||
ContractInfo *bchain.ContractInfo
|
||||
SecondaryCoin string
|
||||
UseSecondaryCoin bool
|
||||
CurrentSecondaryCoinRate float64
|
||||
TxBlocktime int64
|
||||
TxDate string
|
||||
TxBlocktimeSecondaryCoinRate float64
|
||||
CoinName string
|
||||
CoinShortcut string
|
||||
CoinLabel string
|
||||
InternalExplorer bool
|
||||
ChainType bchain.ChainType
|
||||
Address *api.Address
|
||||
AddrStr string
|
||||
Tx *api.Tx
|
||||
Error *api.APIError
|
||||
Blocks *api.Blocks
|
||||
Block *api.Block
|
||||
Info *api.SystemInfo
|
||||
MempoolTxids *api.MempoolTxids
|
||||
Page int
|
||||
PrevPage int
|
||||
NextPage int
|
||||
PagingRange []int
|
||||
PageParams template.URL
|
||||
TOSLink string
|
||||
SendTxHex string
|
||||
Status string
|
||||
NonZeroBalanceTokens bool
|
||||
TokenId string
|
||||
URI string
|
||||
ContractInfo *bchain.ContractInfo
|
||||
SecondaryCoin string
|
||||
UseSecondaryCoin bool
|
||||
CurrentSecondaryCoinRate float64
|
||||
CurrentTicker *common.CurrencyRatesTicker
|
||||
TxBlocktime int64
|
||||
TxDate string
|
||||
TxSecondaryCoinRate float64
|
||||
TxTicker *common.CurrencyRatesTicker
|
||||
}
|
||||
|
||||
func (s *PublicServer) parseTemplates() []*template.Template {
|
||||
templateFuncMap := template.FuncMap{
|
||||
"formatTime": formatTime,
|
||||
"formatUnixTime": formatUnixTime,
|
||||
"timeSpan": timeSpan,
|
||||
"unixTimeSpan": unixTimeSpan,
|
||||
"amountSpan": s.amountSpan,
|
||||
"tokenAmountSpan": s.tokenAmountSpan,
|
||||
"amountSatsSpan": s.amountSatsSpan,
|
||||
"addressAliasSpan": addressAliasSpan,
|
||||
"formatAmount": s.formatAmount,
|
||||
"formatAmountWithDecimals": formatAmountWithDecimals,
|
||||
"amount": s.amount,
|
||||
"formatInt64": formatInt64,
|
||||
"formatInt": formatInt,
|
||||
"formatUint32": formatUint32,
|
||||
"formatBigInt": formatBigInt,
|
||||
"setTxToTemplateData": setTxToTemplateData,
|
||||
"feePerByte": feePerByte,
|
||||
"isOwnAddress": isOwnAddress,
|
||||
@ -537,7 +545,7 @@ func (s *PublicServer) parseTemplates() []*template.Template {
|
||||
}
|
||||
t := template.New(filepath.Base(filenames[0])).Funcs(templateFuncMap)
|
||||
for _, filename := range filenames {
|
||||
b, err := ioutil.ReadFile(filename)
|
||||
b, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -614,12 +622,14 @@ func relativeTime(d int64) string {
|
||||
return strconv.FormatInt(d, 10) + u
|
||||
}
|
||||
|
||||
func formatUnixTime(ut int64) template.HTML {
|
||||
func unixTimeSpan(ut int64) template.HTML {
|
||||
t := time.Unix(ut, 0)
|
||||
return formatTime(&t)
|
||||
return timeSpan(&t)
|
||||
}
|
||||
|
||||
func formatTime(t *time.Time) template.HTML {
|
||||
var timeNow = time.Now
|
||||
|
||||
func timeSpan(t *time.Time) template.HTML {
|
||||
if t == nil {
|
||||
return ""
|
||||
}
|
||||
@ -627,7 +637,7 @@ func formatTime(t *time.Time) template.HTML {
|
||||
if u <= 0 {
|
||||
return ""
|
||||
}
|
||||
d := time.Now().Unix() - u
|
||||
d := timeNow().Unix() - u
|
||||
f := t.UTC().Format("2006-01-02 15:04:05")
|
||||
if d < 0 {
|
||||
return template.HTML(f)
|
||||
@ -694,9 +704,7 @@ func appendAmountSpan(rv *strings.Builder, class, amount, shortcut, txDate strin
|
||||
rv.WriteString("</span>")
|
||||
}
|
||||
|
||||
func (s *PublicServer) amount(a *api.Amount, td *TemplateData, classes string) template.HTML {
|
||||
primary := s.formatAmount(a)
|
||||
var rv strings.Builder
|
||||
func appendWrappingAmountSpan(rv *strings.Builder, primary, symbol, classes string) {
|
||||
rv.WriteString(`<span class="amt`)
|
||||
if classes != "" {
|
||||
rv.WriteString(` `)
|
||||
@ -705,15 +713,21 @@ func (s *PublicServer) amount(a *api.Amount, td *TemplateData, classes string) t
|
||||
rv.WriteString(`" cc="`)
|
||||
rv.WriteString(primary)
|
||||
rv.WriteString(" ")
|
||||
rv.WriteString(td.CoinShortcut)
|
||||
rv.WriteString(symbol)
|
||||
rv.WriteString(`">`)
|
||||
}
|
||||
|
||||
func (s *PublicServer) amountSpan(a *api.Amount, td *TemplateData, classes string) template.HTML {
|
||||
primary := s.formatAmount(a)
|
||||
var rv strings.Builder
|
||||
appendWrappingAmountSpan(&rv, primary, td.CoinShortcut, classes)
|
||||
appendAmountSpan(&rv, "prim-amt", primary, td.CoinShortcut, "")
|
||||
if td.SecondaryCoin != "" {
|
||||
base, err := strconv.ParseFloat(primary, 64)
|
||||
p, err := strconv.ParseFloat(primary, 64)
|
||||
if err == nil {
|
||||
currentSecondary := strconv.FormatFloat(base*td.CurrentSecondaryCoinRate, 'f', 2, 64)
|
||||
blocktimeSecondary := ""
|
||||
// if tx is specified, secondary amount is at the time of tx and current amount with class "csec-amt"
|
||||
currentSecondary := strconv.FormatFloat(p*td.CurrentSecondaryCoinRate, 'f', 2, 64)
|
||||
txSecondary := ""
|
||||
// if tx is specified, compute secondary amount is at the time of tx and amount with current rate is returned with class "csec-amt"
|
||||
if td.Tx != nil {
|
||||
if td.Tx.Blocktime != td.TxBlocktime {
|
||||
td.TxBlocktime = td.Tx.Blocktime
|
||||
@ -721,17 +735,18 @@ func (s *PublicServer) amount(a *api.Amount, td *TemplateData, classes string) t
|
||||
secondary := strings.ToLower(td.SecondaryCoin)
|
||||
ticker, _ := s.db.FiatRatesFindTicker(&date, secondary, "")
|
||||
if ticker != nil {
|
||||
td.TxBlocktimeSecondaryCoinRate = float64(ticker.Rates[secondary])
|
||||
td.TxSecondaryCoinRate = float64(ticker.Rates[secondary])
|
||||
// the ticker is from the midnight, valid for the whole day before
|
||||
td.TxDate = date.Add(-1 * time.Second).Format("2006-01-02")
|
||||
td.TxTicker = ticker
|
||||
}
|
||||
}
|
||||
if td.TxBlocktimeSecondaryCoinRate != 0 {
|
||||
blocktimeSecondary = strconv.FormatFloat(base*td.TxBlocktimeSecondaryCoinRate, 'f', 2, 64)
|
||||
if td.TxSecondaryCoinRate != 0 {
|
||||
txSecondary = strconv.FormatFloat(p*td.TxSecondaryCoinRate, 'f', 2, 64)
|
||||
}
|
||||
}
|
||||
if blocktimeSecondary != "" {
|
||||
appendAmountSpan(&rv, "sec-amt", blocktimeSecondary, td.SecondaryCoin, td.TxDate)
|
||||
if txSecondary != "" {
|
||||
appendAmountSpan(&rv, "sec-amt", txSecondary, td.SecondaryCoin, td.TxDate)
|
||||
appendAmountSpan(&rv, "csec-amt", currentSecondary, td.SecondaryCoin, "")
|
||||
} else {
|
||||
appendAmountSpan(&rv, "sec-amt", currentSecondary, td.SecondaryCoin, "")
|
||||
@ -742,6 +757,92 @@ func (s *PublicServer) amount(a *api.Amount, td *TemplateData, classes string) t
|
||||
return template.HTML(rv.String())
|
||||
}
|
||||
|
||||
func (s *PublicServer) amountSatsSpan(a *api.Amount, td *TemplateData, classes string) template.HTML {
|
||||
var sats string
|
||||
if s.chainParser.GetChainType() == bchain.ChainEthereumType {
|
||||
sats = a.DecimalString(9) // Gwei
|
||||
} else {
|
||||
sats = a.String()
|
||||
}
|
||||
var rv strings.Builder
|
||||
rv.WriteString(`<span`)
|
||||
if classes != "" {
|
||||
rv.WriteString(` class="`)
|
||||
rv.WriteString(classes)
|
||||
rv.WriteString(`"`)
|
||||
}
|
||||
rv.WriteString(` cc="`)
|
||||
rv.WriteString(sats)
|
||||
rv.WriteString(`">`)
|
||||
appendAmountSpan(&rv, "", sats, "", "")
|
||||
rv.WriteString("</span>")
|
||||
return template.HTML(rv.String())
|
||||
}
|
||||
|
||||
func getContractRate(ticker *common.CurrencyRatesTicker, contract string) (float64, bool) {
|
||||
if ticker == nil {
|
||||
return 0, false
|
||||
}
|
||||
rate, found := ticker.TokenRates[contract]
|
||||
return float64(rate), found
|
||||
}
|
||||
|
||||
func (s *PublicServer) tokenAmountSpan(t *api.TokenTransfer, td *TemplateData, classes string) template.HTML {
|
||||
primary := formatAmountWithDecimals(t.Value, t.Decimals)
|
||||
var rv strings.Builder
|
||||
appendWrappingAmountSpan(&rv, primary, td.CoinShortcut, classes)
|
||||
appendAmountSpan(&rv, "prim-amt", primary, t.Symbol, "")
|
||||
if td.SecondaryCoin != "" {
|
||||
var currentBase, currentSecondary, txBase, txSecondary string
|
||||
p, err := strconv.ParseFloat(primary, 64)
|
||||
if err == nil {
|
||||
ticker := td.CurrentTicker
|
||||
baseRate, found := getContractRate(ticker, t.Contract)
|
||||
if !found {
|
||||
now := time.Now().UTC()
|
||||
ticker, _ = s.db.FiatRatesFindTicker(&now, "", t.Contract)
|
||||
baseRate, found = getContractRate(ticker, t.Contract)
|
||||
}
|
||||
if found {
|
||||
base := p * baseRate
|
||||
currentBase = strconv.FormatFloat(base, 'g', s.chainParser.AmountDecimals(), 64)
|
||||
currentSecondary = strconv.FormatFloat(base*td.CurrentSecondaryCoinRate, 'f', 2, 64)
|
||||
}
|
||||
ticker = td.TxTicker
|
||||
baseRate, found = getContractRate(ticker, t.Contract)
|
||||
if !found {
|
||||
ticker, _ = s.db.FiatRatesFindTicker(&td.TxTicker.Timestamp, "", t.Contract)
|
||||
baseRate, found = getContractRate(ticker, t.Contract)
|
||||
}
|
||||
if found {
|
||||
base := p * baseRate
|
||||
txBase = strconv.FormatFloat(base, 'g', s.chainParser.AmountDecimals(), 64)
|
||||
txSecondary = strconv.FormatFloat(base*td.CurrentSecondaryCoinRate, 'f', 2, 64)
|
||||
}
|
||||
}
|
||||
if txBase != "" {
|
||||
appendAmountSpan(&rv, "base-amt", txBase, td.CoinShortcut, td.TxDate)
|
||||
if currentBase != "" {
|
||||
appendAmountSpan(&rv, "cbase-amt", currentBase, td.CoinShortcut, "")
|
||||
}
|
||||
} else if currentBase != "" {
|
||||
appendAmountSpan(&rv, "base-amt", currentBase, td.CoinShortcut, "")
|
||||
}
|
||||
if txSecondary != "" {
|
||||
appendAmountSpan(&rv, "sec-amt", txSecondary, td.SecondaryCoin, td.TxDate)
|
||||
if currentSecondary != "" {
|
||||
appendAmountSpan(&rv, "csec-amt", currentSecondary, td.SecondaryCoin, "")
|
||||
}
|
||||
} else if currentSecondary != "" {
|
||||
appendAmountSpan(&rv, "sec-amt", currentSecondary, td.SecondaryCoin, "")
|
||||
} else {
|
||||
appendAmountSpan(&rv, "sec-amt", "-", "", "")
|
||||
}
|
||||
}
|
||||
rv.WriteString("</span>")
|
||||
return template.HTML(rv.String())
|
||||
}
|
||||
|
||||
func formatInt(i int) template.HTML {
|
||||
return formatInt64(int64(i))
|
||||
}
|
||||
@ -794,13 +895,50 @@ func formatInt64(i int64) template.HTML {
|
||||
return template.HTML(rv.String())
|
||||
}
|
||||
|
||||
func formatBigInt(i *big.Int) template.HTML {
|
||||
if i == nil {
|
||||
return ""
|
||||
}
|
||||
s := i.String()
|
||||
var rv strings.Builder
|
||||
appendSeparatedNumberSpans(&rv, s, "ns")
|
||||
return template.HTML(rv.String())
|
||||
}
|
||||
|
||||
func addressAliasSpan(a string, td *TemplateData) template.HTML {
|
||||
var alias api.AddressAlias
|
||||
var found bool
|
||||
if td.Block != nil {
|
||||
alias, found = td.Block.AddressAliases[a]
|
||||
} else if td.Address != nil {
|
||||
alias, found = td.Address.AddressAliases[a]
|
||||
} else if td.Tx != nil {
|
||||
alias, found = td.Tx.AddressAliases[a]
|
||||
}
|
||||
var rv strings.Builder
|
||||
if !found {
|
||||
rv.WriteString(`<span class="copyable">`)
|
||||
rv.WriteString(a)
|
||||
} else {
|
||||
rv.WriteString(`<span class="copyable" cc="`)
|
||||
rv.WriteString(a)
|
||||
rv.WriteString(`" alias-type="`)
|
||||
rv.WriteString(alias.Type)
|
||||
rv.WriteString(`">`)
|
||||
rv.WriteString(alias.Alias)
|
||||
}
|
||||
rv.WriteString("</span>")
|
||||
return template.HTML(rv.String())
|
||||
}
|
||||
|
||||
// called from template to support txdetail.html functionality
|
||||
func setTxToTemplateData(td *TemplateData, tx *api.Tx) *TemplateData {
|
||||
td.Tx = tx
|
||||
// reset the TxBlocktimeSecondaryCoinRate if different Blocktime
|
||||
if td.TxBlocktime != tx.Blocktime {
|
||||
td.TxBlocktime = 0
|
||||
td.TxBlocktimeSecondaryCoinRate = 0
|
||||
td.TxSecondaryCoinRate = 0
|
||||
td.TxTicker = nil
|
||||
}
|
||||
return td
|
||||
}
|
||||
@ -875,7 +1013,7 @@ func (s *PublicServer) explorerSpendingTx(w http.ResponseWriter, r *http.Request
|
||||
if ec == nil {
|
||||
spendingTx, err := s.api.GetSpendingTxid(tx, n)
|
||||
if err == nil && spendingTx != "" {
|
||||
http.Redirect(w, r, joinURL("/tx/", spendingTx), 302)
|
||||
http.Redirect(w, r, joinURL("/tx/", spendingTx), http.StatusFound)
|
||||
return noTpl, nil, nil
|
||||
}
|
||||
}
|
||||
@ -1102,22 +1240,22 @@ func (s *PublicServer) explorerSearch(w http.ResponseWriter, r *http.Request) (t
|
||||
if len(q) > 0 {
|
||||
address, err = s.api.GetXpubAddress(q, 0, 1, api.AccountDetailsBasic, &api.AddressFilter{Vout: api.AddressFilterVoutOff}, 0)
|
||||
if err == nil {
|
||||
http.Redirect(w, r, joinURL("/xpub/", url.QueryEscape(address.AddrStr)), 302)
|
||||
http.Redirect(w, r, joinURL("/xpub/", url.QueryEscape(address.AddrStr)), http.StatusFound)
|
||||
return noTpl, nil, nil
|
||||
}
|
||||
block, err = s.api.GetBlock(q, 0, 1)
|
||||
if err == nil {
|
||||
http.Redirect(w, r, joinURL("/block/", block.Hash), 302)
|
||||
http.Redirect(w, r, joinURL("/block/", block.Hash), http.StatusFound)
|
||||
return noTpl, nil, nil
|
||||
}
|
||||
tx, err = s.api.GetTransaction(q, false, false)
|
||||
if err == nil {
|
||||
http.Redirect(w, r, joinURL("/tx/", tx.Txid), 302)
|
||||
http.Redirect(w, r, joinURL("/tx/", tx.Txid), http.StatusFound)
|
||||
return noTpl, nil, nil
|
||||
}
|
||||
address, err = s.api.GetAddress(q, 0, 1, api.AccountDetailsBasic, &api.AddressFilter{Vout: api.AddressFilterVoutOff})
|
||||
if err == nil {
|
||||
http.Redirect(w, r, joinURL("/address/", address.AddrStr), 302)
|
||||
http.Redirect(w, r, joinURL("/address/", address.AddrStr), http.StatusFound)
|
||||
return noTpl, nil, nil
|
||||
}
|
||||
}
|
||||
@ -1465,7 +1603,7 @@ func (s *PublicServer) apiSendTx(r *http.Request, apiVersion int) (interface{},
|
||||
var hex string
|
||||
s.metrics.ExplorerViews.With(common.Labels{"action": "api-sendtx"}).Inc()
|
||||
if r.Method == http.MethodPost {
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
data, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return nil, api.NewAPIError("Missing tx blob", true)
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -63,6 +63,12 @@ select {
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
outline: 0;
|
||||
box-shadow: none;
|
||||
border-color: #00854d;
|
||||
}
|
||||
|
||||
.badge {
|
||||
vertical-align: middle;
|
||||
filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.15));
|
||||
@ -73,6 +79,20 @@ select {
|
||||
--bs-badge-border-radius: 0.6rem;
|
||||
}
|
||||
|
||||
.accordion {
|
||||
--bs-accordion-border-radius: 10px;
|
||||
--bs-accordion-inner-border-radius: calc(10px - 1px);
|
||||
--bs-accordion-color: var(--bs-body-color);
|
||||
--bs-accordion-active-color: var(--bs-body-color);
|
||||
--bs-accordion-active-bg: white;
|
||||
--bs-accordion-btn-active-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='black'><path fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/></svg>");
|
||||
}
|
||||
|
||||
.accordion-button:focus {
|
||||
outline: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.bb-group {
|
||||
border: 0.6rem solid #f6f6f6;
|
||||
background-color: #f6f6f6;
|
||||
@ -180,7 +200,7 @@ span.btn-paging:hover {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
background-size: cover;
|
||||
background-image: url("data:image/svg+xml, %3Csvg style='background: white%3B' width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M7.24976 12.5C10.1493 12.5 12.4998 10.1495 12.4998 7.25C12.4998 4.35051 10.1493 2 7.24976 2C4.35026 2 1.99976 4.35051 1.99976 7.25C1.99976 10.1495 4.35026 12.5 7.24976 12.5Z' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' /%3E%3Cpath d='M10.962 10.9625L13.9996 14.0001' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' /%3E%3C/svg%3E");
|
||||
background-image: url("data:image/svg+xml, %3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M7.24976 12.5C10.1493 12.5 12.4998 10.1495 12.4998 7.25C12.4998 4.35051 10.1493 2 7.24976 2C4.35026 2 1.99976 4.35051 1.99976 7.25C1.99976 10.1495 4.35026 12.5 7.24976 12.5Z' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' /%3E%3Cpath d='M10.962 10.9625L13.9996 14.0001' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' /%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.navbar-form ::placeholder {
|
||||
@ -251,6 +271,10 @@ span.btn-paging:hover {
|
||||
color: var(--bs-body-color);
|
||||
}
|
||||
|
||||
.accordion .table.data-table>thead>*>* {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.info-table tbody {
|
||||
display: inline-table;
|
||||
width: 100%;
|
||||
@ -339,12 +363,16 @@ span.btn-paging:hover {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.tx-detail>.head {
|
||||
.tx-detail>.head,
|
||||
.tx-detail>.footer {
|
||||
padding: 1.5rem;
|
||||
border-radius: 10px 10px 0 0;
|
||||
--bs-gutter-x: 0;
|
||||
}
|
||||
|
||||
.tx-detail>.head {
|
||||
border-radius: 10px 10px 0 0;
|
||||
}
|
||||
|
||||
.tx-detail .txid {
|
||||
font-size: 106%;
|
||||
letter-spacing: -0.01em;
|
||||
@ -356,20 +384,38 @@ span.btn-paging:hover {
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.tx-detail>.footer {
|
||||
padding: 1.5rem;
|
||||
|
||||
.tx-detail>.subhead {
|
||||
padding: 1.5rem 1.5rem 0.4rem 1.5rem;
|
||||
--bs-gutter-x: 0;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
color: var(--bs-body-color);
|
||||
}
|
||||
|
||||
.tx-detail>.subhead-2 {
|
||||
padding: 0.3rem 1.5rem 0 1.5rem;
|
||||
--bs-gutter-x: 0;
|
||||
font-size: .875em;
|
||||
color: var(--bs-body-color);
|
||||
}
|
||||
|
||||
.tx-in .col-12,
|
||||
.tx-out .col-12 {
|
||||
.tx-out .col-12,
|
||||
.tx-addr .col-12 {
|
||||
background-color: white;
|
||||
padding: 1.2rem 1.3rem;
|
||||
border-bottom: 1px solid #f6f6f6;
|
||||
}
|
||||
|
||||
.amt-out {
|
||||
padding: 1.2rem 0 1.2rem 1rem;
|
||||
text-align: right;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.tx-in .col-12:last-child,
|
||||
.tx-out .co-12l:last-child {
|
||||
.tx-out .col-12:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
@ -427,8 +473,15 @@ span.btn-paging:hover {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.txerror .copyable::before,
|
||||
.txerror .copied::before {
|
||||
/* turn svg stroke to white */
|
||||
filter: hue-rotate(180deg) brightness(1000%) contrast(100%);
|
||||
}
|
||||
|
||||
.tx-amt .amt:hover,
|
||||
.tx-amt.amt:hover {
|
||||
.tx-amt.amt:hover,
|
||||
.amt-out>.amt:hover {
|
||||
color: var(--bs-body-color);
|
||||
}
|
||||
|
||||
@ -444,9 +497,17 @@ span.btn-paging:hover {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.base-amt {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cbase-amt {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
--bs-tooltip-opacity: 1;
|
||||
--bs-tooltip-max-width: 320px;
|
||||
--bs-tooltip-max-width: 380px;
|
||||
--bs-tooltip-bg: #fff;
|
||||
--bs-tooltip-color: var(--bs-body-color);
|
||||
--bs-tooltip-padding-x: 1rem;
|
||||
@ -454,27 +515,29 @@ span.btn-paging:hover {
|
||||
filter: drop-shadow(0px 24px 64px rgba(22, 27, 45, 0.25));
|
||||
}
|
||||
|
||||
.amt-tooltip {
|
||||
.l-tooltip {
|
||||
text-align: start;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.amt-tooltip .prim-amt,
|
||||
.amt-tooltip .sec-amt,
|
||||
.amt-tooltip .csec-amt {
|
||||
.l-tooltip .prim-amt,
|
||||
.l-tooltip .sec-amt,
|
||||
.l-tooltip .csec-amt,
|
||||
.l-tooltip .base-amt,
|
||||
.l-tooltip .cbase-amt {
|
||||
display: initial;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.amt-dec {
|
||||
font-size: 97%;
|
||||
}
|
||||
|
||||
.amt-tooltip .amt-time {
|
||||
.l-tooltip .amt-time {
|
||||
padding-right: 3rem;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.amt-dec {
|
||||
font-size: 95%;
|
||||
}
|
||||
|
||||
.unconfirmed {
|
||||
color: white;
|
||||
background-color: #c51e13;
|
||||
@ -539,6 +602,16 @@ span.btn-paging:hover {
|
||||
.table.data-table>:not(caption)>*>* {
|
||||
padding: 0.8rem 0.4rem;
|
||||
}
|
||||
|
||||
.tx-in .col-12,
|
||||
.tx-out .col-12,
|
||||
.tx-addr .col-12 {
|
||||
padding: 0.7rem 1.1rem;
|
||||
}
|
||||
|
||||
.amt-out {
|
||||
padding: 0.7rem 0 0.7rem 1rem
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 769px) {
|
||||
|
||||
@ -50,7 +50,19 @@ function amountTooltip() {
|
||||
const prim = this.querySelector(".prim-amt");
|
||||
const sec = this.querySelector(".sec-amt");
|
||||
const csec = this.querySelector(".csec-amt");
|
||||
const base = this.querySelector(".base-amt");
|
||||
const cbase = this.querySelector(".cbase-amt");
|
||||
let s = `${prim.outerHTML}<br>`;
|
||||
if (base) {
|
||||
let t = base.getAttribute("tm");
|
||||
if (!t) {
|
||||
t = "now";
|
||||
}
|
||||
s += `<span class="amt-time">${t}</span>${base.outerHTML}<br>`;
|
||||
}
|
||||
if (cbase) {
|
||||
s += `<span class="amt-time">now</span>${cbase.outerHTML}<br>`;
|
||||
}
|
||||
if (sec) {
|
||||
let t = sec.getAttribute("tm");
|
||||
if (!t) {
|
||||
@ -59,9 +71,15 @@ function amountTooltip() {
|
||||
s += `<span class="amt-time">${t}</span>${sec.outerHTML}<br>`;
|
||||
}
|
||||
if (csec) {
|
||||
s += `<span class="amt-time">now</span>${csec.outerHTML}`;
|
||||
s += `<span class="amt-time">now</span>${csec.outerHTML}<br>`;
|
||||
}
|
||||
return `<span class="amt-tooltip">${s}</span>`;
|
||||
return `<span class="l-tooltip">${s}</span>`;
|
||||
}
|
||||
|
||||
function addressAliasTooltip() {
|
||||
const type = this.getAttribute("alias-type");
|
||||
const address = this.getAttribute("cc");
|
||||
return `<span class="l-tooltip">${type}<br>${address}</span>`;
|
||||
}
|
||||
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
@ -78,6 +96,13 @@ window.addEventListener("DOMContentLoaded", () => {
|
||||
);
|
||||
}
|
||||
|
||||
document
|
||||
.querySelectorAll("[alias-type]")
|
||||
.forEach(
|
||||
(e) =>
|
||||
new bootstrap.Tooltip(e, { title: addressAliasTooltip, html: true })
|
||||
);
|
||||
|
||||
document
|
||||
.querySelectorAll("[tt]")
|
||||
.forEach((e) => new bootstrap.Tooltip(e, { title: e.getAttribute("tt") }));
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<div class="col-md-10 order-2 order-md-1">
|
||||
<h1>{{if $addr.ContractInfo}}Contract {{$addr.ContractInfo.Name}}{{if $addr.ContractInfo.Symbol}} ({{$addr.ContractInfo.Symbol}}){{end}}{{else}}Address{{end}}</h1>
|
||||
<h5 class="col-12 d-flex h-data pb-2"><span class="ellipsis copyable">{{$addr.AddrStr}}</span></h5>
|
||||
<h4>{{amount $addr.BalanceSat $data "copyable"}}</h4>
|
||||
<h4>{{amountSpan $addr.BalanceSat $data "copyable"}}</h4>
|
||||
</div>
|
||||
<div class="col-md-2 order-1 order-md-2 d-flex justify-content-center justify-content-md-end mb-3 mb-md-0">
|
||||
<div id="qrcode"></div>
|
||||
@ -42,7 +42,7 @@
|
||||
{{end}}
|
||||
<tr>
|
||||
<td style="width: 25%;">Balance</td>
|
||||
<td>{{amount $addr.BalanceSat $data "copyable"}}</td>
|
||||
<td>{{amountSpan $addr.BalanceSat $data "copyable"}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Transactions</td>
|
||||
@ -74,7 +74,7 @@
|
||||
{{range $t := $addr.Tokens}}
|
||||
{{if eq $t.Type "ERC20"}}
|
||||
<tr>
|
||||
<td class="data ellipsis"><a href="/address/{{$t.Contract}}">{{if $t.Name}}{{$t.Name}}{{else}}{{$t.Contract}}{{end}}</a></td>
|
||||
<td class="ellipsis"><a href="/address/{{$t.Contract}}">{{if $t.Name}}{{$t.Name}}{{else}}{{$t.Contract}}{{end}}</a></td>
|
||||
<td>{{formatAmountWithDecimals $t.BalanceSat $t.Decimals}} {{$t.Symbol}}</td>
|
||||
<td>{{$t.Transfers}}</td>
|
||||
</tr>
|
||||
@ -99,7 +99,7 @@
|
||||
{{range $t := $addr.Tokens}}
|
||||
{{if eq $t.Type "ERC721"}}
|
||||
<tr>
|
||||
<td class="data ellipsis"><a href="/address/{{$t.Contract}}">{{if $t.Name}}{{$t.Name}}{{else}}{{$t.Contract}}{{end}}</a></td>
|
||||
<td class="ellipsis"><a href="/address/{{$t.Contract}}">{{if $t.Name}}{{$t.Name}}{{else}}{{$t.Contract}}{{end}}</a></td>
|
||||
<td>
|
||||
{{range $i, $iv := $t.Ids}}{{if $i}}, {{end}}<a href="/nft/{{$t.Contract}}/{{formatAmountWithDecimals $iv 0}}">{{formatAmountWithDecimals $iv 0}}</a>{{end}}
|
||||
</td>
|
||||
@ -126,7 +126,7 @@
|
||||
{{range $t := $addr.Tokens}}
|
||||
{{if eq $t.Type "ERC1155"}}
|
||||
<tr>
|
||||
<td class="data ellipsis"><a href="/address/{{$t.Contract}}">{{if $t.Name}}{{$t.Name}}{{else}}{{$t.Contract}}{{end}}</a></td>
|
||||
<td class="ellipsis"><a href="/address/{{$t.Contract}}">{{if $t.Name}}{{$t.Name}}{{else}}{{$t.Contract}}{{end}}</a></td>
|
||||
<td>
|
||||
{{range $i, $iv := $t.MultiTokenValues}}{{if $i}}, {{end}}{{$iv.Value}} of ID <a href="/nft/{{$t.Contract}}/{{$iv.Id}}">{{$iv.Id}}</a>{{end}}
|
||||
</td>
|
||||
@ -143,15 +143,15 @@
|
||||
{{else}}
|
||||
<tr>
|
||||
<td style="width: 25%;">Total Received</td>
|
||||
<td>{{amount $addr.TotalReceivedSat $data "copyable"}}</td>
|
||||
<td>{{amountSpan $addr.TotalReceivedSat $data "copyable"}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total Sent</td>
|
||||
<td>{{amount $addr.TotalSentSat $data "copyable"}}</td>
|
||||
<td>{{amountSpan $addr.TotalSentSat $data "copyable"}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Final Balance</td>
|
||||
<td>{{amount $addr.BalanceSat $data "copyable"}}</td>
|
||||
<td>{{amountSpan $addr.BalanceSat $data "copyable"}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>No. Transactions</td>
|
||||
@ -169,7 +169,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 25%;">Unconfirmed Balance</td>
|
||||
<td>{{amount $addr.UnconfirmedBalanceSat $data "copyable"}}</td>
|
||||
<td>{{amountSpan $addr.UnconfirmedBalanceSat $data "copyable"}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>No. Transactions</td>
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Timestamp</td>
|
||||
<td>{{formatUnixTime $b.Time}}</td>
|
||||
<td>{{unixTimeSpan $b.Time}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Size (bytes)</td>
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
<tr>
|
||||
<td><a href="/block/{{$b.Height}}">{{formatUint32 $b.Height}}</a></td>
|
||||
<td class="ellipsis">{{$b.Hash}}</td>
|
||||
<td>{{formatUnixTime $b.Time}}</td>
|
||||
<td>{{unixTimeSpan $b.Time}}</td>
|
||||
<td class="text-end">{{formatUint32 $b.Txs}}</td>
|
||||
<td class="text-end">{{formatUint32 $b.Size}}</td>
|
||||
</tr>
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Last Block Update</td>
|
||||
<td>{{formatTime $bb.LastBlockTime}}</td>
|
||||
<td>{{timeSpan $bb.LastBlockTime}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Mempool in Sync</td>
|
||||
@ -44,7 +44,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Last Mempool Update</td>
|
||||
<td>{{formatTime $bb.LastMempoolTime}}</td>
|
||||
<td>{{timeSpan $bb.LastMempoolTime}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Transactions in Mempool</td>
|
||||
@ -53,11 +53,11 @@
|
||||
{{if $bb.HasFiatRates}}
|
||||
<tr>
|
||||
<td>Current Fiat rates</td>
|
||||
<td>{{formatTime $bb.CurrentFiatRatesTime}}</td>
|
||||
<td>{{timeSpan $bb.CurrentFiatRatesTime}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Historical Fiat rates</td>
|
||||
<td>{{formatTime $bb.HistoricalFiatRatesTime}}{{if $bb.HasTokenFiatRates}}<br>tokens {{formatTime $bb.HistoricalTokenFiatRatesTime}}{{end}}</td>
|
||||
<td>{{timeSpan $bb.HistoricalFiatRatesTime}}{{if $bb.HasTokenFiatRates}}<br><span class="fw-normal">tokens</span> {{timeSpan $bb.HistoricalTokenFiatRatesTime}}{{end}}</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
<tr>
|
||||
@ -77,7 +77,7 @@
|
||||
{{if $be.BackendError}}
|
||||
<tr>
|
||||
<td>Backend Error</td>
|
||||
<td class="data text-danger">{{$be.BackendError}}</td>
|
||||
<td class="text-danger">{{$be.BackendError}}</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
<tr>
|
||||
@ -135,7 +135,7 @@
|
||||
{{if $be.Warnings}}
|
||||
<tr>
|
||||
<td>Warnings</td>
|
||||
<td class="data text-warning">{{$be.Warnings}}</td>
|
||||
<td class="text-warning">{{$be.Warnings}}</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
{{range $tx := $txs}}
|
||||
<tr>
|
||||
<td class="ellipsis"><a href="/tx/{{$tx.Txid}}">{{$tx.Txid}}</a></td>
|
||||
<td>{{formatUnixTime $tx.Time}}</td>
|
||||
<td>{{unixTimeSpan $tx.Time}}</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
|
||||
@ -2,32 +2,32 @@
|
||||
<h1>NFT Token Detail</h1>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<table class="table data-table">
|
||||
<table class="table data-table info-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 25%;">Token ID</td>
|
||||
<td class="data">{{$data.TokenId}}</td>
|
||||
<td>{{$data.TokenId}}</td>
|
||||
</tr>
|
||||
<tr id="name" style="display: none;">
|
||||
<td>NTF Name</td>
|
||||
<td class="data"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr id="description" style="display: none;">
|
||||
<td>NTF Description</td>
|
||||
<td class="data"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Contract</td>
|
||||
<td class="data"><a href="/address/{{$data.ContractInfo.Contract}}">{{$data.ContractInfo.Contract}}</a> {{$data.ContractInfo.Name}}</td>
|
||||
<td><a href="/address/{{$data.ContractInfo.Contract}}">{{$data.ContractInfo.Contract}}</a><br>{{$data.ContractInfo.Name}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Contract type</td>
|
||||
<td class="data">{{$data.ContractInfo.Type}}</td>
|
||||
<td>{{$data.ContractInfo.Type}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-md-6" id="image"></div>
|
||||
<div class="col-md-6 mt-4" id="image"></div>
|
||||
</div>
|
||||
<div id="metadatablock">
|
||||
<h5>Metadata</h5>
|
||||
@ -38,7 +38,7 @@
|
||||
<script type="text/javascript">
|
||||
function showImage(s) {
|
||||
const img = document.createElement("img");
|
||||
img.className="border w-100";
|
||||
img.className="border w-100 bg-white";
|
||||
img.src = s;
|
||||
const src = document.getElementById("image");
|
||||
src.appendChild(img);
|
||||
@ -46,7 +46,7 @@
|
||||
}
|
||||
function nftInfo(id,text) {
|
||||
const src = document.getElementById(id);
|
||||
src.getElementsByClassName('data')[0].innerText=text;
|
||||
src.getElementsByTagName("td")[1].innerText=text;
|
||||
src.style.display='';
|
||||
}
|
||||
async function getMetadata(url) {
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
{{if $tx.Confirmations}}
|
||||
<tr>
|
||||
<td>Mined Time</td>
|
||||
<td>{{formatUnixTime $tx.Blocktime}}</td>
|
||||
<td>{{unixTimeSpan $tx.Blocktime}}</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
<tr>
|
||||
@ -29,7 +29,7 @@
|
||||
{{if eq $tx.EthereumSpecific.Status 1}}
|
||||
<td><span class="badge bg-success">Success</span></td>
|
||||
{{else}}
|
||||
{{if eq $tx.EthereumSpecific.Status 1}}
|
||||
{{if eq $tx.EthereumSpecific.Status -1}}
|
||||
<td>Pending</td>
|
||||
{{else}}
|
||||
<td>Unknown</td>
|
||||
@ -41,24 +41,24 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Value</td>
|
||||
<td>{{amount $tx.ValueOutSat $data "copyable"}}</td>
|
||||
<td>{{amountSpan $tx.ValueOutSat $data "copyable"}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Gas Used / Limit</td>
|
||||
<td>{{if $tx.EthereumSpecific.GasUsed}}{{$tx.EthereumSpecific.GasUsed}}{{else}}pending{{end}} / {{$tx.EthereumSpecific.GasLimit}}</td>
|
||||
<td>{{if $tx.EthereumSpecific.GasUsed}}{{formatBigInt $tx.EthereumSpecific.GasUsed}}{{else}}pending{{end}} / {{formatBigInt $tx.EthereumSpecific.GasLimit}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Gas Price</td>
|
||||
<td>{{amount $tx.EthereumSpecific.GasPrice $data "copyable"}}</td>
|
||||
<td>{{amountSpan $tx.EthereumSpecific.GasPrice $data "copyable"}} <span class="fw-normal ps-3">({{amountSatsSpan $tx.EthereumSpecific.GasPrice $data "copyable"}} Gwei)</span></td>
|
||||
</tr>
|
||||
{{else}}
|
||||
<tr>
|
||||
<td>Total Input</td>
|
||||
<td>{{amount $tx.ValueInSat $data "copyable"}}</td>
|
||||
<td>{{amountSpan $tx.ValueInSat $data "copyable"}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total Output</td>
|
||||
<td>{{amount $tx.ValueOutSat $data "copyable"}}</td>
|
||||
<td>{{amountSpan $tx.ValueOutSat $data "copyable"}}</td>
|
||||
</tr>
|
||||
{{if $tx.VSize}}
|
||||
<tr>
|
||||
@ -77,7 +77,7 @@
|
||||
{{if $tx.FeesSat}}
|
||||
<tr>
|
||||
<td>Fees</td>
|
||||
<td>{{amount $tx.FeesSat $data "copyable"}}{{if $tx.Size}} ({{feePerByte $tx}}){{end}}</td>
|
||||
<td>{{amountSpan $tx.FeesSat $data "copyable"}}{{if $tx.Size}} ({{feePerByte $tx}}){{end}}</td>
|
||||
</tr>{{end}}
|
||||
{{if not $tx.Confirmations}}
|
||||
<tr>
|
||||
@ -93,51 +93,63 @@
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>Details</h3>
|
||||
<div>
|
||||
<div class="pt-1">
|
||||
{{template "txdetail" .}}
|
||||
</div>
|
||||
{{if eq .ChainType 1}}
|
||||
{{if $tx.EthereumSpecific.ParsedData}}
|
||||
{{if $tx.EthereumSpecific.ParsedData.Function }}
|
||||
<div class="data-div">
|
||||
<div class="pt-2">
|
||||
<h5>Input Data</h5>
|
||||
<div class="row">
|
||||
{{if $tx.EthereumSpecific.ParsedData.Name}}<div class="col-6">{{$tx.EthereumSpecific.ParsedData.Name}}</div>{{end}}{{if $tx.EthereumSpecific.ParsedData.MethodId}}<div class="col-6">Method ID: {{$tx.EthereumSpecific.ParsedData.MethodId}}</div>{{end}}
|
||||
{{if $tx.EthereumSpecific.ParsedData.Function}}<div class="col-12">Function: {{$tx.EthereumSpecific.ParsedData.Function}}</div>{{end}}
|
||||
{{if $tx.EthereumSpecific.ParsedData.Params}}
|
||||
<div class="col-12">
|
||||
<table class="table data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 5%;">#</th>
|
||||
<th style="width: 25%;">Type</th>
|
||||
<th>Data</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range $i,$p := $tx.EthereumSpecific.ParsedData.Params}}
|
||||
<tr>
|
||||
<td>{{$i}}</td>
|
||||
<td>{{$p.Type}}</td>
|
||||
<td>
|
||||
{{range $j,$v := $p.Values}}
|
||||
{{if $j}}<br>{{end}}
|
||||
{{if hasPrefix $p.Type "address"}}<a href="/address/{{$v}}">{{$v}}</a>{{else}}{{$v}}{{end}}
|
||||
<div class="accordion" id="inputData">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="inputDataHeading">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#inputDataBody" aria-expanded="false" aria-controls="inputDataBody">
|
||||
<h5 class="mb-0">{{if $tx.EthereumSpecific.ParsedData.Name}}{{$tx.EthereumSpecific.ParsedData.Name}} {{end}}{{if $tx.EthereumSpecific.ParsedData.MethodId}} <span class="fw-normal small" tt="4-byte signature">{{$tx.EthereumSpecific.ParsedData.MethodId}}</span>{{end}}</h5>
|
||||
</button>
|
||||
</h2>
|
||||
<div id="inputDataBody" class="accordion-collapse collapse" aria-labelledby="inputDataHeading" data-bs-parent="#inputData">
|
||||
<div class="accordion-body">
|
||||
<div class="row">
|
||||
<div class="col-12"><span class="copyable" style="overflow-wrap: break-word;">{{$tx.EthereumSpecific.Data}}</span></div>
|
||||
<div class="col-12 pt-2"><span class="copyable">{{$tx.EthereumSpecific.ParsedData.Function}}</span></div>
|
||||
{{if $tx.EthereumSpecific.ParsedData.Params}}
|
||||
<div class="col-12">
|
||||
<table class="table data-table mt-2 mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 5%;">#</th>
|
||||
<th style="width: 20%;">Type</th>
|
||||
<th>Data</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range $i,$p := $tx.EthereumSpecific.ParsedData.Params}}
|
||||
<tr>
|
||||
<td>{{$i}}</td>
|
||||
<td>{{$p.Type}}</td>
|
||||
<td>
|
||||
{{range $j,$v := $p.Values}}
|
||||
{{if $j}}<br>{{end}}
|
||||
{{if hasPrefix $p.Type "address"}}<a href="/address/{{$v}}">{{addressAliasSpan $v $data}}</a>{{else}}<span class="copyable">{{$v}}</span>{{end}}
|
||||
{{end}}
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{end}}
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
<div class="data-div">
|
||||
<div class="pt-4">
|
||||
<h5>Raw Transaction</h5>
|
||||
<div class="json">
|
||||
<pre id="raw"></pre>
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<a href="/tx/{{$tx.Txid}}" class="ellipsis copyable txid">{{$tx.Txid}}</a>
|
||||
{{if $tx.Rbf}}<span class="ps-1" tt="Replace-by-Fee (RBF) transaction, could be overridden"> RBF</span>{{end}}
|
||||
</div>
|
||||
{{if $tx.Blocktime}}<div class="col-xs-5 col-md-4 text-end">{{if $tx.Confirmations}}mined{{else}}first seen{{end}} <span class="txvalue ms-1">{{formatUnixTime $tx.Blocktime}}</span></div>{{end}}
|
||||
{{if $tx.Blocktime}}<div class="col-xs-5 col-md-4 text-end">{{if $tx.Confirmations}}mined{{else}}first seen{{end}} <span class="txvalue ms-1">{{unixTimeSpan $tx.Blocktime}}</span></div>{{end}}
|
||||
</div>
|
||||
<div class="row body">
|
||||
<div class="col-md-5">
|
||||
@ -13,16 +13,16 @@
|
||||
{{range $vin := $tx.Vin}}
|
||||
<div class="col-12{{if $vin.IsOwn}} tx-own{{end}}">
|
||||
{{range $a := $vin.Addresses}}
|
||||
<span class="ellipsis tx-addr copyable">
|
||||
<span class="ellipsis copyable">
|
||||
{{if and (ne $a $addr) $vin.IsAddress}}<a href="/address/{{$a}}">{{$a}}</a>{{else}}{{$a}}{{end}}
|
||||
</span>
|
||||
{{else}}
|
||||
<span class="tx-addr">{{if $vin.Hex}}Unparsed address{{else}}No Inputs (Newly Generated Coins){{end}}</span>
|
||||
{{if $vin.Hex}}Unparsed address{{else}}No Inputs (Newly Generated Coins){{end}}
|
||||
{{end}}
|
||||
{{if $vin.Txid}}
|
||||
<a class="outpoint" href="/tx/{{$vin.Txid}}" tt="Outpoint {{$vin.Txid}},{{$vin.Vout}}">←</a>
|
||||
{{end}}
|
||||
{{if $vin.Addresses}}{{amount $vin.ValueSat $data "tx-amt copyable"}}{{end}}
|
||||
{{if $vin.Addresses}}{{amountSpan $vin.ValueSat $data "tx-amt copyable"}}{{end}}
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="col-12">No Inputs</div>
|
||||
@ -32,31 +32,31 @@
|
||||
<div class="col-md-1 col-xs-12 text-center"> <span class="octicon"></span></div>
|
||||
<div class="col-md-6">
|
||||
<div class="row tx-out">
|
||||
{{range $vout := $tx.Vout}}
|
||||
<div class="col-12{{if $vout.IsOwn}} tx-own{{end}}">
|
||||
{{range $a := $vout.Addresses}}
|
||||
<span class="ellipsis tx-addr copyable">
|
||||
{{if and (ne $a $addr) $vout.IsAddress}}<a href="/address/{{$a}}">{{$a}}</a>{{else}}{{$a}}{{end}}
|
||||
</span>
|
||||
{{else}}
|
||||
<span class="tx-addr">Unparsed address</span>
|
||||
{{end}}
|
||||
<span class="tx-amt">
|
||||
{{amount $vout.ValueSat $data "copyable"}}{{if $vout.Spent}}<a class="spent" href="{{if $vout.SpentTxID}}/tx/{{$vout.SpentTxID}}{{else}}/spending/{{$tx.Txid}}/{{$vout.N}}{{end}}" tt="Spent">→</a>{{else}}<span class="unspent" tt="Unspent">×</span>
|
||||
{{end}}
|
||||
</span>
|
||||
</td>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="col-12">No Outputs</div>
|
||||
{{range $vout := $tx.Vout}}
|
||||
<div class="col-12{{if $vout.IsOwn}} tx-own{{end}}">
|
||||
{{range $a := $vout.Addresses}}
|
||||
<span class="ellipsis copyable">
|
||||
{{if and (ne $a $addr) $vout.IsAddress}}<a href="/address/{{$a}}">{{$a}}</a>{{else}}{{$a}}{{end}}
|
||||
</span>
|
||||
{{else}}
|
||||
Unparsed address
|
||||
{{end}}
|
||||
<span class="tx-amt">
|
||||
{{amountSpan $vout.ValueSat $data "copyable"}}{{if $vout.Spent}}<a class="spent" href="{{if $vout.SpentTxID}}/tx/{{$vout.SpentTxID}}{{else}}/spending/{{$tx.Txid}}/{{$vout.N}}{{end}}" tt="Spent">→</a>{{else}}<span class="unspent" tt="Unspent">×</span>
|
||||
{{end}}
|
||||
</span>
|
||||
</td>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="col-12">No Outputs</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row footer">
|
||||
<div class="col-sm-12 col-md-4">
|
||||
{{if $tx.FeesSat}}
|
||||
Fee {{amount $tx.FeesSat $data "txvalue copyable ms-3"}}
|
||||
Fee {{amountSpan $tx.FeesSat $data "txvalue copyable ms-3"}}
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-8 text-end">
|
||||
@ -64,10 +64,10 @@
|
||||
{{if $tx.Confirmations}}
|
||||
<span class="txvalue">{{formatUint32 $tx.Confirmations}}</span> confirmations
|
||||
{{else}}
|
||||
<span class="txvalue unconfirmed">Unconfirmed Transaction!</span>
|
||||
<span class="txvalue unconfirmed">Unconfirmed Transaction!</span>
|
||||
{{end}}
|
||||
</span>
|
||||
{{amount $tx.ValueOutSat $data "txvalue copyable"}}
|
||||
{{amountSpan $tx.ValueOutSat $data "txvalue copyable"}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,295 +1,203 @@
|
||||
{{define "txdetail"}}{{$cs := .CoinShortcut}}{{$addr := .AddrStr}}{{$tx := .Tx}}{{$data := .}}
|
||||
<div class="tx-detail"{{if eq $tx.EthereumSpecific.Status 0}} style="background-color: #faf2ee;"{{end}}>
|
||||
<div class="row line-bot">
|
||||
<div class="col-xs-7 col-md-8 ellipsis">
|
||||
<a href="/tx/{{$tx.Txid}}">{{$tx.Txid}}</a>
|
||||
{{if eq $tx.EthereumSpecific.Status 1}}<span class="text-success"> ✔</span>{{end}}{{if eq $tx.EthereumSpecific.Status 0}}<span class="text-danger"> ✘</span>{{end}}
|
||||
<div class="tx-detail">
|
||||
<div class="row head{{if eq $tx.EthereumSpecific.Status 0}} txerror{{end}}">
|
||||
<div class="col-xs-7 col-md-8">
|
||||
<a href="/tx/{{$tx.Txid}}" class="ellipsis copyable txid">{{$tx.Txid}}</a>
|
||||
{{if $tx.Rbf}}<span class="ps-1" tt="Replace-by-Fee (RBF) transaction, could be overridden"> RBF</span>{{end}}
|
||||
</div>
|
||||
{{- if $tx.Blocktime}}<div class="col-xs-5 col-md-4 text-muted text-right">{{if $tx.Confirmations}}mined{{else}}first seen{{end}} {{formatUnixTime $tx.Blocktime}}</div>{{end -}}
|
||||
{{if $tx.Blocktime}}<div class="col-xs-5 col-md-4 text-end">{{if $tx.Confirmations}}mined{{else}}first seen{{end}} <span class="txvalue ms-1">{{unixTimeSpan $tx.Blocktime}}</span></div>{{end}}
|
||||
{{if $tx.EthereumSpecific.ParsedData}}
|
||||
{{if $tx.EthereumSpecific.ParsedData.Name}}<div class="col-6">{{$tx.EthereumSpecific.ParsedData.Name}}</div>{{end}}{{if $tx.EthereumSpecific.ParsedData.MethodId}}<div class="col-6">Method ID: {{$tx.EthereumSpecific.ParsedData.MethodId}}</div>{{end}}
|
||||
{{if $tx.EthereumSpecific.ParsedData.Name}}<div class="col-12 small"><span class="txvalue">{{$tx.EthereumSpecific.ParsedData.Name}}</span>{{if $tx.EthereumSpecific.ParsedData.MethodId}}<span class="ms-1" tt="4-byte signature"> ({{$tx.EthereumSpecific.ParsedData.MethodId}})</span>{{end}}</div>{{else}}
|
||||
{{if $tx.EthereumSpecific.ParsedData.MethodId}}<div class="col-12 small txvalue"><span tt="4-byte signature">{{$tx.EthereumSpecific.ParsedData.MethodId}}</span></div>{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if $tx.EthereumSpecific.Error}}<div class="col-12">Error: {{$tx.EthereumSpecific.Error}}</div>{{end}}
|
||||
{{if eq $tx.EthereumSpecific.Status 0}}<div col-12><span class="badge bg-danger">Failed</span>{{if $tx.EthereumSpecific.Error}}<span class="small ms-1">{{$tx.EthereumSpecific.Error}}</span>{{end}}</div>{{end}}
|
||||
</div>
|
||||
<div class="row line-mid">
|
||||
<div class="row body">
|
||||
<div class="col-md-4">
|
||||
<div class="row tx-in">
|
||||
<table class="table data-table">
|
||||
<tbody>
|
||||
{{- range $vin := $tx.Vin -}}
|
||||
<tr{{if $vin.IsOwn}} class="tx-own"{{end}}>
|
||||
<td>
|
||||
{{- range $a := $vin.Addresses -}}
|
||||
<span class="ellipsis tx-addr">
|
||||
{{if and (ne $a $addr) $vin.IsAddress}}<a href="/address/{{$a}}">{{$a}}</a>{{else}}{{$a}}{{end}}
|
||||
</span>
|
||||
{{- else -}}
|
||||
<span class="tx-addr">Unparsed address</span>
|
||||
{{- end -}}
|
||||
</td>
|
||||
</tr>
|
||||
{{- else -}}
|
||||
<tr>
|
||||
<td>No Inputs</td>
|
||||
</tr>
|
||||
{{- end -}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{range $vin := $tx.Vin}}
|
||||
<div class="col-12{{if $vin.IsOwn}} tx-own{{end}}">
|
||||
{{range $a := $vin.Addresses}}
|
||||
<span class="ellipsis">
|
||||
{{if and (ne $a $addr) $vin.IsAddress}}<a href="/address/{{$a}}">{{addressAliasSpan $a $data}}</a>{{else}}{{addressAliasSpan $a $data}}{{end}}
|
||||
</span>
|
||||
{{else}}
|
||||
Unparsed address
|
||||
{{end}}
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="col-12">No Inputs</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-1 col-xs-12 text-center">
|
||||
<svg class="octicon" viewBox="0 0 8 16">
|
||||
<path fill-rule="evenodd" d="M7.5 8l-5 5L1 11.5 4.75 8 1 4.5 2.5 3l5 5z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="col-md-1 col-xs-12 text-center"> <span class="octicon"></span></div>
|
||||
<div class="col-md-4">
|
||||
<div class="row tx-out">
|
||||
<table class="table data-table">
|
||||
<tbody>
|
||||
{{- range $vout := $tx.Vout -}}
|
||||
<tr{{if $vout.IsOwn}} class="tx-own"{{end}}>
|
||||
<td>
|
||||
{{- range $a := $vout.Addresses -}}
|
||||
<span class="ellipsis tx-addr">
|
||||
{{- if and (ne $a $addr) $vout.IsAddress}}<a href="/address/{{$a}}">{{$a}}</a>{{else}}{{$a}}{{- end -}}
|
||||
</span>
|
||||
{{- else -}}
|
||||
<span class="tx-addr">Unparsed address</span>
|
||||
{{- end -}}
|
||||
</td>
|
||||
</tr>
|
||||
{{- else -}}
|
||||
<tr>
|
||||
<td>No Outputs</td>
|
||||
</tr>
|
||||
{{- end -}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{range $vout := $tx.Vout}}
|
||||
<div class="col-12{{if $vout.IsOwn}} tx-own{{end}}">
|
||||
{{range $a := $vout.Addresses}}
|
||||
<span class="ellipsis">
|
||||
{{if and (ne $a $addr) $vout.IsAddress}}<a href="/address/{{$a}}">{{addressAliasSpan $a $data}}</a>{{else}}{{addressAliasSpan $a $data}}{{end}}
|
||||
</span>
|
||||
{{else}}
|
||||
Unparsed address
|
||||
{{end}}
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="col-12">No Outputs</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-right" style="padding: .4rem 0;overflow-wrap: break-word;">
|
||||
{{formatAmount $tx.ValueOutSat}} {{$cs}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 amt-out">{{amountSpan $tx.ValueOutSat $data "tx-out copyable"}}</div>
|
||||
</div>
|
||||
|
||||
{{if eq $tx.EthereumSpecific.Type 1}}
|
||||
<div class="row line-top" style="padding: 15px 0 6px 15px;font-weight: bold;">
|
||||
Contract creation
|
||||
</div>
|
||||
<div class="row" style="padding: 2px 15px;">
|
||||
<div class="col-md-4">
|
||||
<div class="row tx-in">
|
||||
<table class="table data-table">
|
||||
<tbody>
|
||||
<tr{{if isOwnAddress $data $tx.EthereumSpecific.CreatedContract}} class="tx-own"{{end}}>
|
||||
<td>
|
||||
<span class="ellipsis tx-addr">{{if ne $tx.EthereumSpecific.CreatedContract $addr}}<a href="/address/{{$tx.EthereumSpecific.CreatedContract}}">{{$tx.EthereumSpecific.CreatedContract}}</a>{{else}}{{$tx.EthereumSpecific.CreatedContract}}{{end}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="row subhead">
|
||||
Contract creation
|
||||
</div>
|
||||
<div class="row body">
|
||||
<div class="col-md-4">
|
||||
<div class="row tx-in">
|
||||
<div class="col-12 ellipsis{{if isOwnAddress $data $tx.EthereumSpecific.CreatedContract}} tx-own{{end}}">
|
||||
{{if ne $tx.EthereumSpecific.CreatedContract $addr}}<a href="/address/{{$tx.EthereumSpecific.CreatedContract}}">{{addressAliasSpan $tx.EthereumSpecific.CreatedContract $data}}</a>{{else}}{{addressAliasSpan $tx.EthereumSpecific.CreatedContract $data}}{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if $tx.EthereumSpecific.InternalTransfers}}
|
||||
<div class="row line-top" style="padding: 15px 0 6px 15px;font-weight: bold;">
|
||||
<div class="row subhead">
|
||||
Internal Transactions
|
||||
</div>
|
||||
{{- range $tt := $tx.EthereumSpecific.InternalTransfers -}}
|
||||
{{if eq $tt.Type 1}}Contract creation{{end}}
|
||||
{{if eq $tt.Type 2}}Contract destruction{{end}}
|
||||
<div class="row" style="padding: 2px 15px;">
|
||||
{{range $tt := $tx.EthereumSpecific.InternalTransfers}}
|
||||
{{if eq $tt.Type 1}}<div class="row subhead-2">Contract creation</div>{{end}}
|
||||
{{if eq $tt.Type 2}}<div class="row subhead-2">Contract destruction</div>{{end}}
|
||||
<div class="row body">
|
||||
<div class="col-md-4">
|
||||
<div class="row tx-in">
|
||||
<table class="table data-table">
|
||||
<tbody>
|
||||
<tr{{if isOwnAddress $data $tt.From}} class="tx-own"{{end}}>
|
||||
<td>
|
||||
<span class="ellipsis tx-addr">{{if ne $tt.From $addr}}<a href="/address/{{$tt.From}}">{{$tt.From}}</a>{{else}}{{$tt.From}}{{end}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="row tx-addr">
|
||||
<div class="col-12 ellipsis{{if isOwnAddress $data $tt.From}} tx-own{{end}}">
|
||||
{{if ne $tt.From $addr}}<a href="/address/{{$tt.From}}">{{addressAliasSpan $tt.From $data}}</a>{{else}}{{addressAliasSpan $tt.From $data}}{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-1 col-xs-12 text-center">
|
||||
<svg class="octicon" viewBox="0 0 8 16">
|
||||
<path fill-rule="evenodd" d="M7.5 8l-5 5L1 11.5 4.75 8 1 4.5 2.5 3l5 5z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="col-md-1 col-xs-12 text-center"> <span class="octicon"></span></div>
|
||||
<div class="col-md-4">
|
||||
<div class="row tx-out">
|
||||
<table class="table data-table">
|
||||
<tbody>
|
||||
<tr{{if isOwnAddress $data $tt.To}} class="tx-own"{{end}}>
|
||||
<td>
|
||||
<span class="ellipsis tx-addr">{{if ne $tt.To $addr}}<a href="/address/{{$tt.To}}">{{$tt.To}}</a>{{else}}{{$tt.To}}{{end}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="row tx-addr">
|
||||
<div class="col-12 ellipsis{{if isOwnAddress $data $tt.To}} tx-own{{end}}">
|
||||
{{if ne $tt.To $addr}}<a href="/address/{{$tt.To}}">{{addressAliasSpan $tt.To $data}}</a>{{else}}{{addressAliasSpan $tt.To $data}}{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-right" style="padding: .4rem 0;overflow-wrap: break-word;">{{formatAmount $tt.Value}} {{$cs}}</div>
|
||||
<div class="col-md-3 amt-out">{{amountSpan $tt.Value $data "tx-out copyable"}}</div>
|
||||
</div>
|
||||
{{- end -}}
|
||||
<div class="row" style="padding: 6px 15px;"></div>
|
||||
{{- end -}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{- if tokenTransfersCount $tx "ERC20" -}}
|
||||
<div class="row line-top" style="padding: 15px 0 6px 15px;font-weight: bold;">
|
||||
{{if tokenTransfersCount $tx "ERC20"}}
|
||||
<div class="row subhead">
|
||||
ERC20 Token Transfers
|
||||
</div>
|
||||
{{- range $tt := $tx.TokenTransfers -}}
|
||||
{{range $tt := $tx.TokenTransfers}}
|
||||
{{if eq $tt.Type "ERC20"}}
|
||||
<div class="row" style="padding: 2px 15px;">
|
||||
<div class="row body">
|
||||
<div class="col-md-4">
|
||||
<div class="row tx-in">
|
||||
<table class="table data-table">
|
||||
<tbody>
|
||||
<tr{{if isOwnAddress $data $tt.From}} class="tx-own"{{end}}>
|
||||
<td>
|
||||
<span class="ellipsis tx-addr">{{if ne $tt.From $addr}}<a href="/address/{{$tt.From}}">{{$tt.From}}</a>{{else}}{{$tt.From}}{{end}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="row tx-addr">
|
||||
<div class="col-12 ellipsis{{if isOwnAddress $data $tt.From}} tx-own{{end}}">
|
||||
{{if ne $tt.From $addr}}<a href="/address/{{$tt.From}}">{{addressAliasSpan $tt.From $data}}</a>{{else}}{{addressAliasSpan $tt.From $data}}{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-1 col-xs-12 text-center">
|
||||
<svg class="octicon" viewBox="0 0 8 16">
|
||||
<path fill-rule="evenodd" d="M7.5 8l-5 5L1 11.5 4.75 8 1 4.5 2.5 3l5 5z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="col-md-1 col-xs-12 text-center"> <span class="octicon"></span></div>
|
||||
<div class="col-md-4">
|
||||
<div class="row tx-out">
|
||||
<table class="table data-table">
|
||||
<tbody>
|
||||
<tr{{if isOwnAddress $data $tt.To}} class="tx-own"{{end}}>
|
||||
<td>
|
||||
<span class="ellipsis tx-addr">{{if ne $tt.To $addr}}<a href="/address/{{$tt.To}}">{{$tt.To}}</a>{{else}}{{$tt.To}}{{end}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="row tx-addr">
|
||||
<div class="col-12 ellipsis{{if isOwnAddress $data $tt.To}} tx-own{{end}}">
|
||||
{{if ne $tt.To $addr}}<a href="/address/{{$tt.To}}">{{addressAliasSpan $tt.To $data}}</a>{{else}}{{addressAliasSpan $tt.To $data}}{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-right" style="padding: .4rem 0;overflow-wrap: break-word;">{{formatAmountWithDecimals $tt.Value $tt.Decimals}} {{$tt.Symbol}}</div>
|
||||
<div class="col-md-3 amt-out">{{tokenAmountSpan $tt $data "tx-out copyable"}}</div>
|
||||
</div>
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
<div class="row" style="padding: 6px 15px;"></div>
|
||||
{{- end -}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{- if tokenTransfersCount $tx "ERC721" -}}
|
||||
<div class="row line-top" style="padding: 15px 0 6px 15px;font-weight: bold;">
|
||||
{{if tokenTransfersCount $tx "ERC721"}}
|
||||
<div class="row subhead">
|
||||
ERC721 Token Transfers
|
||||
</div>
|
||||
{{- range $tt := $tx.TokenTransfers -}}
|
||||
{{range $tt := $tx.TokenTransfers}}
|
||||
{{if eq $tt.Type "ERC721"}}
|
||||
<div class="row" style="padding: 2px 15px;">
|
||||
<div class="row body">
|
||||
<div class="col-md-4">
|
||||
<div class="row tx-in">
|
||||
<table class="table data-table">
|
||||
<tbody>
|
||||
<tr{{if isOwnAddress $data $tt.From}} class="tx-own"{{end}}>
|
||||
<td>
|
||||
<span class="ellipsis tx-addr">{{if ne $tt.From $addr}}<a href="/address/{{$tt.From}}">{{$tt.From}}</a>{{else}}{{$tt.From}}{{end}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="row tx-addr">
|
||||
<div class="col-12 ellipsis{{if isOwnAddress $data $tt.From}} tx-own{{end}}">
|
||||
{{if ne $tt.From $addr}}<a href="/address/{{$tt.From}}">{{addressAliasSpan $tt.From $data}}</a>{{else}}{{addressAliasSpan $tt.From $data}}{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-1 col-xs-12 text-center">
|
||||
<svg class="octicon" viewBox="0 0 8 16">
|
||||
<path fill-rule="evenodd" d="M7.5 8l-5 5L1 11.5 4.75 8 1 4.5 2.5 3l5 5z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="col-md-1 col-xs-12 text-center"> <span class="octicon"></span></div>
|
||||
<div class="col-md-4">
|
||||
<div class="row tx-out">
|
||||
<table class="table data-table">
|
||||
<tbody>
|
||||
<tr{{if isOwnAddress $data $tt.To}} class="tx-own"{{end}}>
|
||||
<td>
|
||||
<span class="ellipsis tx-addr">{{if ne $tt.To $addr}}<a href="/address/{{$tt.To}}">{{$tt.To}}</a>{{else}}{{$tt.To}}{{end}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="row tx-addr">
|
||||
<div class="col-12 ellipsis{{if isOwnAddress $data $tt.To}} tx-own{{end}}">
|
||||
{{if ne $tt.To $addr}}<a href="/address/{{$tt.To}}">{{addressAliasSpan $tt.To $data}}</a>{{else}}{{addressAliasSpan $tt.To $data}}{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-right" style="padding: .4rem 0;overflow-wrap: break-word;">ID <a href="/nft/{{$tt.Contract}}/{{$tt.Value}}">{{$tt.Value}}</a> {{$tt.Symbol}}</div>
|
||||
<div class="col-md-3 amt-out">ID <a href="/nft/{{$tt.Contract}}/{{$tt.Value}}">{{$tt.Value}}</a> {{$tt.Symbol}}</div>
|
||||
</div>
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
<div class="row" style="padding: 6px 15px;"></div>
|
||||
{{- end -}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{- if tokenTransfersCount $tx "ERC1155" -}}
|
||||
<div class="row line-top" style="padding: 15px 0 6px 15px;font-weight: bold;">
|
||||
{{if tokenTransfersCount $tx "ERC1155"}}
|
||||
<div class="row subhead">
|
||||
ERC1155 Token Transfers
|
||||
</div>
|
||||
{{- range $tt := $tx.TokenTransfers -}}
|
||||
{{range $tt := $tx.TokenTransfers}}
|
||||
{{if eq $tt.Type "ERC1155"}}
|
||||
<div class="row" style="padding: 2px 15px;">
|
||||
<div class="row body">
|
||||
<div class="col-md-4">
|
||||
<div class="row tx-in">
|
||||
<table class="table data-table">
|
||||
<tbody>
|
||||
<tr{{if isOwnAddress $data $tt.From}} class="tx-own"{{end}}>
|
||||
<td>
|
||||
<span class="ellipsis tx-addr">{{if ne $tt.From $addr}}<a href="/address/{{$tt.From}}">{{$tt.From}}</a>{{else}}{{$tt.From}}{{end}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="row tx-addr">
|
||||
<div class="col-12 ellipsis{{if isOwnAddress $data $tt.From}} tx-own{{end}}">
|
||||
{{if ne $tt.From $addr}}<a href="/address/{{$tt.From}}">{{addressAliasSpan $tt.From $data}}</a>{{else}}{{addressAliasSpan $tt.From $data}}{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-1 col-xs-12 text-center">
|
||||
<svg class="octicon" viewBox="0 0 8 16">
|
||||
<path fill-rule="evenodd" d="M7.5 8l-5 5L1 11.5 4.75 8 1 4.5 2.5 3l5 5z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="col-md-1 col-xs-12 text-center"> <span class="octicon"></span></div>
|
||||
<div class="col-md-4">
|
||||
<div class="row tx-out">
|
||||
<table class="table data-table">
|
||||
<tbody>
|
||||
<tr{{if isOwnAddress $data $tt.To}} class="tx-own"{{end}}>
|
||||
<td>
|
||||
<span class="ellipsis tx-addr">{{if ne $tt.To $addr}}<a href="/address/{{$tt.To}}">{{$tt.To}}</a>{{else}}{{$tt.To}}{{end}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="row tx-addr">
|
||||
<div class="col-12 ellipsis{{if isOwnAddress $data $tt.To}} tx-own{{end}}">
|
||||
{{if ne $tt.To $addr}}<a href="/address/{{$tt.To}}">{{addressAliasSpan $tt.To $data}}</a>{{else}}{{addressAliasSpan $tt.To $data}}{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-right" style="padding: .4rem 0;overflow-wrap: break-word;">
|
||||
{{- range $i, $iv := $tt.MultiTokenValues -}}
|
||||
<div class="col-md-3 amt-out">
|
||||
{{range $i, $iv := $tt.MultiTokenValues}}
|
||||
{{if $i}}, {{end}}{{$iv.Value}} {{$tt.Symbol}} of ID <a href="/nft/{{$tt.Contract}}/{{$iv.Id}}">{{$iv.Id}}</a>
|
||||
{{- end -}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
<div class="row" style="padding: 6px 15px;"></div>
|
||||
{{- end -}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
<div class="row line-top">
|
||||
<div class="col-xs-6 col-sm-4 col-md-4">
|
||||
{{- if $tx.FeesSat -}}
|
||||
<span class="txvalues txvalues-default">Fee: {{formatAmount $tx.FeesSat}} {{$cs}}</span>
|
||||
{{- end -}}
|
||||
<div class="row footer">
|
||||
<div class="col-sm-12 col-md-4">
|
||||
{{if $tx.FeesSat}}
|
||||
Fee {{amountSpan $tx.FeesSat $data "txvalue copyable ms-3"}}
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="col-xs-6 col-sm-8 col-md-8 text-right">
|
||||
{{- if $tx.Confirmations -}}
|
||||
<span class="txvalues txvalues-success">{{$tx.Confirmations}} Confirmations</span>
|
||||
{{- else -}}
|
||||
<span class="txvalues txvalues-danger ng-hide">Unconfirmed Transaction!</span>
|
||||
{{- end -}}
|
||||
<span class="txvalues txvalues-primary">{{formatAmount $tx.ValueOutSat}} {{$cs}}</span>
|
||||
<div class="col-sm-12 col-md-8 text-end">
|
||||
<span class="me-4">
|
||||
{{if $tx.Confirmations}}
|
||||
<span class="txvalue">{{formatUint32 $tx.Confirmations}}</span> confirmations
|
||||
{{else}}
|
||||
<span class="txvalue unconfirmed">Unconfirmed Transaction!</span>
|
||||
{{end}}
|
||||
</span>
|
||||
{{amountSpan $tx.ValueOutSat $data "txvalue copyable"}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<div class="col-md-10 order-2 order-md-1">
|
||||
<h1>XPUB</h1>
|
||||
<h5 class="col-12 d-flex h-data pb-2"><span class="ellipsis copyable">{{$addr.AddrStr}}</span></h5>
|
||||
<h4>{{amount $addr.BalanceSat $data "copyable"}}</h4>
|
||||
<h4>{{amountSpan $addr.BalanceSat $data "copyable"}}</h4>
|
||||
</div>
|
||||
<div class="col-md-2 order-1 order-md-2 d-flex justify-content-center justify-content-md-end mb-3 mb-md-0">
|
||||
<div id="qrcode"></div>
|
||||
@ -21,23 +21,23 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 25%;">Total Received</td>
|
||||
<td class="data">{{amount $addr.TotalReceivedSat $data "copyable"}}</td>
|
||||
<td>{{amountSpan $addr.TotalReceivedSat $data "copyable"}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total Sent</td>
|
||||
<td class="data">{{amount $addr.TotalSentSat $data "copyable"}}</td>
|
||||
<td>{{amountSpan $addr.TotalSentSat $data "copyable"}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Final Balance</td>
|
||||
<td class="data">{{amount $addr.BalanceSat $data "copyable"}}</td>
|
||||
<td>{{amountSpan $addr.BalanceSat $data "copyable"}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>No. Transactions</td>
|
||||
<td class="data">{{formatInt $addr.Txs}}</td>
|
||||
<td>{{formatInt $addr.Txs}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Used XPUB Addresses</td>
|
||||
<td class="data">{{formatInt $addr.UsedTokens}}</td>
|
||||
<td>{{formatInt $addr.UsedTokens}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -57,7 +57,7 @@
|
||||
{{range $t := $addr.Tokens}}
|
||||
<tr>
|
||||
<td class="ellipsis"><a href="/address/{{$t.Name}}" class="copyable">{{$t.Name}}</a></td>
|
||||
<td>{{amount $t.BalanceSat $data "copyable"}}</td>
|
||||
<td>{{amountSpan $t.BalanceSat $data "copyable"}}</td>
|
||||
<td>{{formatInt $t.Transfers}}</td>
|
||||
<td>{{$t.Path}}</td>
|
||||
</tr>
|
||||
@ -87,7 +87,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 25%;">Unconfirmed Balance</td>
|
||||
<td>{{amount $addr.UnconfirmedBalanceSat $data "copyable"}}</td>
|
||||
<td>{{amountSpan $addr.UnconfirmedBalanceSat $data "copyable"}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>No. Transactions</td>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user