Add type api.Amount for proper formatting of amounts in json
This commit is contained in:
parent
d01081fd83
commit
9c142663ce
114
api/types.go
114
api/types.go
@ -2,7 +2,6 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"blockbook/bchain"
|
"blockbook/bchain"
|
||||||
"blockbook/bchain/coins/eth"
|
|
||||||
"blockbook/common"
|
"blockbook/common"
|
||||||
"blockbook/db"
|
"blockbook/db"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -42,6 +41,17 @@ func NewAPIError(s string, public bool) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Amount is datatype holding amounts
|
||||||
|
type Amount big.Int
|
||||||
|
|
||||||
|
// MarshalJSON Amount serialization
|
||||||
|
func (a *Amount) MarshalJSON() (out []byte, err error) {
|
||||||
|
if a == nil {
|
||||||
|
return []byte(`"0"`), nil
|
||||||
|
}
|
||||||
|
return []byte(`"` + (*big.Int)(a).String() + `"`), nil
|
||||||
|
}
|
||||||
|
|
||||||
// ScriptSig contains input script
|
// ScriptSig contains input script
|
||||||
type ScriptSig struct {
|
type ScriptSig struct {
|
||||||
Hex string `json:"hex"`
|
Hex string `json:"hex"`
|
||||||
@ -58,8 +68,7 @@ type Vin struct {
|
|||||||
AddrDesc bchain.AddressDescriptor `json:"-"`
|
AddrDesc bchain.AddressDescriptor `json:"-"`
|
||||||
Addresses []string `json:"addresses"`
|
Addresses []string `json:"addresses"`
|
||||||
Searchable bool `json:"-"`
|
Searchable bool `json:"-"`
|
||||||
Value string `json:"value"`
|
ValueSat *Amount `json:"value,omitempty"`
|
||||||
ValueSat big.Int `json:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScriptPubKey contains output script and addresses derived from it
|
// ScriptPubKey contains output script and addresses derived from it
|
||||||
@ -74,8 +83,7 @@ type ScriptPubKey struct {
|
|||||||
|
|
||||||
// Vout contains information about single transaction output
|
// Vout contains information about single transaction output
|
||||||
type Vout struct {
|
type Vout struct {
|
||||||
Value string `json:"value"`
|
ValueSat *Amount `json:"value,omitempty"`
|
||||||
ValueSat big.Int `json:"-"`
|
|
||||||
N int `json:"n"`
|
N int `json:"n"`
|
||||||
ScriptPubKey ScriptPubKey `json:"scriptPubKey"`
|
ScriptPubKey ScriptPubKey `json:"scriptPubKey"`
|
||||||
Spent bool `json:"spent"`
|
Spent bool `json:"spent"`
|
||||||
@ -86,50 +94,57 @@ type Vout struct {
|
|||||||
|
|
||||||
// Erc20Token contains info about ERC20 token held by an address
|
// Erc20Token contains info about ERC20 token held by an address
|
||||||
type Erc20Token struct {
|
type Erc20Token struct {
|
||||||
Contract string `json:"contract"`
|
Contract string `json:"contract"`
|
||||||
Txs int `json:"txs"`
|
Txs int `json:"txs"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Symbol string `json:"symbol"`
|
Symbol string `json:"symbol"`
|
||||||
Decimals int `json:"decimals"`
|
Decimals int `json:"decimals"`
|
||||||
Balance string `json:"balance,omitempty"`
|
BalanceSat *Amount `json:"balance,omitempty"`
|
||||||
BalanceSat string `json:"balanceSat,omitempty"`
|
ContractIndex string `json:"-"`
|
||||||
ContractIndex string `json:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Erc20Transfer contains info about ERC20 transfer done in a transaction
|
// Erc20Transfer contains info about ERC20 transfer done in a transaction
|
||||||
type Erc20Transfer struct {
|
type Erc20Transfer struct {
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
To string `json:"to"`
|
To string `json:"to"`
|
||||||
Contract string `json:"contract"`
|
Contract string `json:"contract"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Symbol string `json:"symbol"`
|
Symbol string `json:"symbol"`
|
||||||
Tokens string `json:"tokens"`
|
Decimals int `json:"decimals"`
|
||||||
|
Tokens *Amount `json:"tokens"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EthereumSpecific contains ethereum specific transaction data
|
||||||
|
type EthereumSpecific struct {
|
||||||
|
Status int `json:"status"` // 1 OK, 0 Fail, -1 pending
|
||||||
|
Nonce uint64 `json:"nonce"`
|
||||||
|
GasLimit *big.Int `json:"gaslimit"`
|
||||||
|
GasUsed *big.Int `json:"gasused"`
|
||||||
|
GasPrice *Amount `json:"gasprice"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tx holds information about a transaction
|
// Tx holds information about a transaction
|
||||||
type Tx struct {
|
type Tx struct {
|
||||||
Txid string `json:"txid"`
|
Txid string `json:"txid"`
|
||||||
Version int32 `json:"version,omitempty"`
|
Version int32 `json:"version,omitempty"`
|
||||||
Locktime uint32 `json:"locktime,omitempty"`
|
Locktime uint32 `json:"locktime,omitempty"`
|
||||||
Vin []Vin `json:"vin"`
|
Vin []Vin `json:"vin"`
|
||||||
Vout []Vout `json:"vout"`
|
Vout []Vout `json:"vout"`
|
||||||
Blockhash string `json:"blockhash,omitempty"`
|
Blockhash string `json:"blockhash,omitempty"`
|
||||||
Blockheight int `json:"blockheight"`
|
Blockheight int `json:"blockheight"`
|
||||||
Confirmations uint32 `json:"confirmations"`
|
Confirmations uint32 `json:"confirmations"`
|
||||||
Time int64 `json:"time,omitempty"`
|
Time int64 `json:"time,omitempty"`
|
||||||
Blocktime int64 `json:"blocktime"`
|
Blocktime int64 `json:"blocktime"`
|
||||||
ValueOut string `json:"valueOut"`
|
ValueOut string `json:"valueOut"`
|
||||||
ValueOutSat big.Int `json:"-"`
|
ValueOutSat *Amount `json:"-"`
|
||||||
Size int `json:"size,omitempty"`
|
Size int `json:"size,omitempty"`
|
||||||
ValueIn string `json:"valueIn"`
|
ValueInSat *Amount `json:"valueIn,omitempty"`
|
||||||
ValueInSat big.Int `json:"-"`
|
FeesSat *Amount `json:"fees,omitempty"`
|
||||||
Fees string `json:"fees"`
|
Hex string `json:"hex,omitempty"`
|
||||||
FeesSat big.Int `json:"-"`
|
CoinSpecificData interface{} `json:"-"`
|
||||||
Hex string `json:"hex,omitempty"`
|
CoinSpecificJSON json.RawMessage `json:"-"`
|
||||||
CoinSpecificData interface{} `json:"-"`
|
Erc20Transfers []Erc20Transfer `json:"erc20transfers,omitempty"`
|
||||||
CoinSpecificJSON json.RawMessage `json:"-"`
|
EthereumSpecific *EthereumSpecific `json:"ethereumspecific,omitempty"`
|
||||||
Erc20Transfers []Erc20Transfer `json:"erc20transfers,omitempty"`
|
|
||||||
EthereumSpecific *eth.EthereumTxData `json:"ethereumspecific,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paging contains information about paging for address, blocks and block
|
// Paging contains information about paging for address, blocks and block
|
||||||
@ -152,16 +167,14 @@ const AddressFilterOutputs = -3
|
|||||||
type Address struct {
|
type Address struct {
|
||||||
Paging
|
Paging
|
||||||
AddrStr string `json:"addrStr"`
|
AddrStr string `json:"addrStr"`
|
||||||
Balance string `json:"balance"`
|
BalanceSat *Amount `json:"balance"`
|
||||||
BalanceSat string `json:"balanceSat"`
|
TotalReceivedSat *Amount `json:"totalReceived,omitempty"`
|
||||||
TotalReceived string `json:"totalReceived,omitempty"`
|
TotalSentSat *Amount `json:"totalSent,omitempty"`
|
||||||
TotalSent string `json:"totalSent,omitempty"`
|
UnconfirmedBalanceSat *Amount `json:"unconfirmedBalance"`
|
||||||
UnconfirmedBalance string `json:"unconfirmedBalance"`
|
|
||||||
UnconfirmedBalanceSat string `json:"unconfirmedBalanceSat"`
|
|
||||||
UnconfirmedTxApperances int `json:"unconfirmedTxApperances"`
|
UnconfirmedTxApperances int `json:"unconfirmedTxApperances"`
|
||||||
TxApperances int `json:"txApperances"`
|
TxApperances int `json:"txApperances"`
|
||||||
Transactions []*Tx `json:"txs,omitempty"`
|
Transactions []*Tx `json:"transactions,omitempty"`
|
||||||
Txids []string `json:"transactions,omitempty"`
|
Txids []string `json:"txids,omitempty"`
|
||||||
Nonce string `json:"nonce,omitempty"`
|
Nonce string `json:"nonce,omitempty"`
|
||||||
Erc20Contract *bchain.Erc20Contract `json:"erc20contract,omitempty"`
|
Erc20Contract *bchain.Erc20Contract `json:"erc20contract,omitempty"`
|
||||||
Erc20Tokens []Erc20Token `json:"erc20tokens,omitempty"`
|
Erc20Tokens []Erc20Token `json:"erc20tokens,omitempty"`
|
||||||
@ -172,8 +185,7 @@ type Address struct {
|
|||||||
type AddressUtxo struct {
|
type AddressUtxo struct {
|
||||||
Txid string `json:"txid"`
|
Txid string `json:"txid"`
|
||||||
Vout int32 `json:"vout"`
|
Vout int32 `json:"vout"`
|
||||||
Amount string `json:"amount"`
|
AmountSat *Amount `json:"value"`
|
||||||
AmountSat big.Int `json:"satoshis"`
|
|
||||||
Height int `json:"height,omitempty"`
|
Height int `json:"height,omitempty"`
|
||||||
Confirmations int `json:"confirmations"`
|
Confirmations int `json:"confirmations"`
|
||||||
}
|
}
|
||||||
|
|||||||
51
api/types_test.go
Normal file
51
api/types_test.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// build unittest
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"math/big"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAmount_MarshalJSON(t *testing.T) {
|
||||||
|
type amounts struct {
|
||||||
|
A1 Amount `json:"a1"`
|
||||||
|
A2 Amount `json:"a2,omitempty"`
|
||||||
|
PA1 *Amount `json:"pa1"`
|
||||||
|
PA2 *Amount `json:"pa2,omitempty"`
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
a amounts
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
want: `{"a1":"0","a2":"0","pa1":null}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "1",
|
||||||
|
a: amounts{
|
||||||
|
A1: (Amount)(*big.NewInt(123456)),
|
||||||
|
A2: (Amount)(*big.NewInt(787901)),
|
||||||
|
PA1: (*Amount)(big.NewInt(234567)),
|
||||||
|
PA2: (*Amount)(big.NewInt(890123)),
|
||||||
|
},
|
||||||
|
want: `{"a1":"123456","a2":"787901","pa1":"234567","pa2":"890123"}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
b, err := json.Marshal(&tt.a)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("json.Marshal() error = %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(string(b), tt.want) {
|
||||||
|
t.Errorf("json.Marshal() = %v, want %v", string(b), tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
109
api/worker.go
109
api/worker.go
@ -59,7 +59,7 @@ func (w *Worker) setSpendingTxToVout(vout *Vout, txid string, height uint32) err
|
|||||||
} else if tsp == nil {
|
} else if tsp == nil {
|
||||||
glog.Warning("DB inconsistency: tx ", t, ": not found in txAddresses")
|
glog.Warning("DB inconsistency: tx ", t, ": not found in txAddresses")
|
||||||
} else if len(tsp.Inputs) > int(index) {
|
} else if len(tsp.Inputs) > int(index) {
|
||||||
if tsp.Inputs[index].ValueSat.Cmp(&vout.ValueSat) == 0 {
|
if tsp.Inputs[index].ValueSat.Cmp((*big.Int)(vout.ValueSat)) == 0 {
|
||||||
spentTx, spentHeight, err := w.txCache.GetTransaction(t)
|
spentTx, spentHeight, err := w.txCache.GetTransaction(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Warning("Tx ", t, ": not found")
|
glog.Warning("Tx ", t, ": not found")
|
||||||
@ -113,7 +113,7 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
|
|||||||
var err error
|
var err error
|
||||||
var ta *db.TxAddresses
|
var ta *db.TxAddresses
|
||||||
var erc20t []Erc20Transfer
|
var erc20t []Erc20Transfer
|
||||||
var ethSpecific *eth.EthereumTxData
|
var ethSpecific *EthereumSpecific
|
||||||
var blockhash string
|
var blockhash string
|
||||||
if bchainTx.Confirmations > 0 {
|
if bchainTx.Confirmations > 0 {
|
||||||
if w.chainType == bchain.ChainBitcoinType {
|
if w.chainType == bchain.ChainBitcoinType {
|
||||||
@ -157,7 +157,7 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
|
|||||||
}
|
}
|
||||||
if len(otx.Vout) > int(vin.Vout) {
|
if len(otx.Vout) > int(vin.Vout) {
|
||||||
vout := &otx.Vout[vin.Vout]
|
vout := &otx.Vout[vin.Vout]
|
||||||
vin.ValueSat = vout.ValueSat
|
vin.ValueSat = (*Amount)(&vout.ValueSat)
|
||||||
vin.AddrDesc, vin.Addresses, vin.Searchable, err = w.getAddressesFromVout(vout)
|
vin.AddrDesc, vin.Addresses, vin.Searchable, err = w.getAddressesFromVout(vout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("getAddressesFromVout error %v, vout %+v", err, vout)
|
glog.Errorf("getAddressesFromVout error %v, vout %+v", err, vout)
|
||||||
@ -166,8 +166,7 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
|
|||||||
} else {
|
} else {
|
||||||
if len(tas.Outputs) > int(vin.Vout) {
|
if len(tas.Outputs) > int(vin.Vout) {
|
||||||
output := &tas.Outputs[vin.Vout]
|
output := &tas.Outputs[vin.Vout]
|
||||||
vin.ValueSat = output.ValueSat
|
vin.ValueSat = (*Amount)(&output.ValueSat)
|
||||||
vin.Value = w.chainParser.AmountToDecimalString(&vin.ValueSat)
|
|
||||||
vin.AddrDesc = output.AddrDesc
|
vin.AddrDesc = output.AddrDesc
|
||||||
vin.Addresses, vin.Searchable, err = output.Addresses(w.chainParser)
|
vin.Addresses, vin.Searchable, err = output.Addresses(w.chainParser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -175,8 +174,7 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vin.Value = w.chainParser.AmountToDecimalString(&vin.ValueSat)
|
valInSat.Add(&valInSat, (*big.Int)(vin.ValueSat))
|
||||||
valInSat.Add(&valInSat, &vin.ValueSat)
|
|
||||||
}
|
}
|
||||||
} else if w.chainType == bchain.ChainEthereumType {
|
} else if w.chainType == bchain.ChainEthereumType {
|
||||||
if len(bchainVin.Addresses) > 0 {
|
if len(bchainVin.Addresses) > 0 {
|
||||||
@ -194,8 +192,7 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
|
|||||||
bchainVout := &bchainTx.Vout[i]
|
bchainVout := &bchainTx.Vout[i]
|
||||||
vout := &vouts[i]
|
vout := &vouts[i]
|
||||||
vout.N = i
|
vout.N = i
|
||||||
vout.ValueSat = bchainVout.ValueSat
|
vout.ValueSat = (*Amount)(&bchainVout.ValueSat)
|
||||||
vout.Value = w.chainParser.AmountToDecimalString(&bchainVout.ValueSat)
|
|
||||||
valOutSat.Add(&valOutSat, &bchainVout.ValueSat)
|
valOutSat.Add(&valOutSat, &bchainVout.ValueSat)
|
||||||
vout.ScriptPubKey.Hex = bchainVout.ScriptPubKey.Hex
|
vout.ScriptPubKey.Hex = bchainVout.ScriptPubKey.Hex
|
||||||
vout.ScriptPubKey.AddrDesc, vout.ScriptPubKey.Addresses, vout.ScriptPubKey.Searchable, err = w.getAddressesFromVout(bchainVout)
|
vout.ScriptPubKey.AddrDesc, vout.ScriptPubKey.Addresses, vout.ScriptPubKey.Searchable, err = w.getAddressesFromVout(bchainVout)
|
||||||
@ -242,20 +239,28 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
|
|||||||
Contract: e.Contract,
|
Contract: e.Contract,
|
||||||
From: e.From,
|
From: e.From,
|
||||||
To: e.To,
|
To: e.To,
|
||||||
Tokens: bchain.AmountToDecimalString(&e.Tokens, erc20c.Decimals),
|
Decimals: erc20c.Decimals,
|
||||||
|
Tokens: (*Amount)(&e.Tokens),
|
||||||
Name: erc20c.Name,
|
Name: erc20c.Name,
|
||||||
Symbol: erc20c.Symbol,
|
Symbol: erc20c.Symbol,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ethSpecific = eth.GetEthereumTxData(bchainTx)
|
ethTxData := eth.GetEthereumTxData(bchainTx)
|
||||||
// mempool txs do not have fees yet
|
// mempool txs do not have fees yet
|
||||||
if ethSpecific.GasUsed != nil {
|
if ethTxData.GasUsed != nil {
|
||||||
feesSat.Mul(ethSpecific.GasPriceNum, ethSpecific.GasUsed)
|
feesSat.Mul(ethTxData.GasPrice, ethTxData.GasUsed)
|
||||||
}
|
}
|
||||||
if len(bchainTx.Vout) > 0 {
|
if len(bchainTx.Vout) > 0 {
|
||||||
valInSat = bchainTx.Vout[0].ValueSat
|
valInSat = bchainTx.Vout[0].ValueSat
|
||||||
}
|
}
|
||||||
valOutSat = valInSat
|
valOutSat = valInSat
|
||||||
|
ethSpecific = &EthereumSpecific{
|
||||||
|
GasLimit: ethTxData.GasLimit,
|
||||||
|
GasPrice: (*Amount)(ethTxData.GasPrice),
|
||||||
|
GasUsed: ethTxData.GasUsed,
|
||||||
|
Nonce: ethTxData.Nonce,
|
||||||
|
Status: ethTxData.Status,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// for now do not return size, we would have to compute vsize of segwit transactions
|
// for now do not return size, we would have to compute vsize of segwit transactions
|
||||||
// size:=len(bchainTx.Hex) / 2
|
// size:=len(bchainTx.Hex) / 2
|
||||||
@ -271,15 +276,12 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
|
|||||||
Blockheight: int(height),
|
Blockheight: int(height),
|
||||||
Blocktime: bchainTx.Blocktime,
|
Blocktime: bchainTx.Blocktime,
|
||||||
Confirmations: bchainTx.Confirmations,
|
Confirmations: bchainTx.Confirmations,
|
||||||
Fees: w.chainParser.AmountToDecimalString(&feesSat),
|
FeesSat: (*Amount)(&feesSat),
|
||||||
FeesSat: feesSat,
|
|
||||||
Locktime: bchainTx.LockTime,
|
Locktime: bchainTx.LockTime,
|
||||||
Time: bchainTx.Time,
|
Time: bchainTx.Time,
|
||||||
Txid: bchainTx.Txid,
|
Txid: bchainTx.Txid,
|
||||||
ValueIn: w.chainParser.AmountToDecimalString(&valInSat),
|
ValueInSat: (*Amount)(&valInSat),
|
||||||
ValueInSat: valInSat,
|
ValueOutSat: (*Amount)(&valOutSat),
|
||||||
ValueOut: w.chainParser.AmountToDecimalString(&valOutSat),
|
|
||||||
ValueOutSat: valOutSat,
|
|
||||||
Version: bchainTx.Version,
|
Version: bchainTx.Version,
|
||||||
Hex: bchainTx.Hex,
|
Hex: bchainTx.Hex,
|
||||||
Vin: vins,
|
Vin: vins,
|
||||||
@ -331,7 +333,7 @@ func (t *Tx) getAddrVoutValue(addrDesc bchain.AddressDescriptor) *big.Int {
|
|||||||
var val big.Int
|
var val big.Int
|
||||||
for _, vout := range t.Vout {
|
for _, vout := range t.Vout {
|
||||||
if bytes.Equal(vout.ScriptPubKey.AddrDesc, addrDesc) {
|
if bytes.Equal(vout.ScriptPubKey.AddrDesc, addrDesc) {
|
||||||
val.Add(&val, &vout.ValueSat)
|
val.Add(&val, (*big.Int)(vout.ValueSat))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &val
|
return &val
|
||||||
@ -341,7 +343,7 @@ func (t *Tx) getAddrVinValue(addrDesc bchain.AddressDescriptor) *big.Int {
|
|||||||
var val big.Int
|
var val big.Int
|
||||||
for _, vin := range t.Vin {
|
for _, vin := range t.Vin {
|
||||||
if bytes.Equal(vin.AddrDesc, addrDesc) {
|
if bytes.Equal(vin.AddrDesc, addrDesc) {
|
||||||
val.Add(&val, &vin.ValueSat)
|
val.Add(&val, (*big.Int)(vin.ValueSat))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &val
|
return &val
|
||||||
@ -371,9 +373,8 @@ func (w *Worker) txFromTxAddress(txid string, ta *db.TxAddresses, bi *db.BlockIn
|
|||||||
tai := &ta.Inputs[i]
|
tai := &ta.Inputs[i]
|
||||||
vin := &vins[i]
|
vin := &vins[i]
|
||||||
vin.N = i
|
vin.N = i
|
||||||
vin.ValueSat = tai.ValueSat
|
vin.ValueSat = (*Amount)(&tai.ValueSat)
|
||||||
vin.Value = w.chainParser.AmountToDecimalString(&vin.ValueSat)
|
valInSat.Add(&valInSat, &tai.ValueSat)
|
||||||
valInSat.Add(&valInSat, &vin.ValueSat)
|
|
||||||
vin.Addresses, vin.Searchable, err = tai.Addresses(w.chainParser)
|
vin.Addresses, vin.Searchable, err = tai.Addresses(w.chainParser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("tai.Addresses error %v, tx %v, input %v, tai %+v", err, txid, i, tai)
|
glog.Errorf("tai.Addresses error %v, tx %v, input %v, tai %+v", err, txid, i, tai)
|
||||||
@ -384,9 +385,8 @@ func (w *Worker) txFromTxAddress(txid string, ta *db.TxAddresses, bi *db.BlockIn
|
|||||||
tao := &ta.Outputs[i]
|
tao := &ta.Outputs[i]
|
||||||
vout := &vouts[i]
|
vout := &vouts[i]
|
||||||
vout.N = i
|
vout.N = i
|
||||||
vout.ValueSat = tao.ValueSat
|
vout.ValueSat = (*Amount)(&tao.ValueSat)
|
||||||
vout.Value = w.chainParser.AmountToDecimalString(&vout.ValueSat)
|
valOutSat.Add(&valOutSat, &tao.ValueSat)
|
||||||
valOutSat.Add(&valOutSat, &vout.ValueSat)
|
|
||||||
vout.ScriptPubKey.Addresses, vout.ScriptPubKey.Searchable, err = tao.Addresses(w.chainParser)
|
vout.ScriptPubKey.Addresses, vout.ScriptPubKey.Searchable, err = tao.Addresses(w.chainParser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("tai.Addresses error %v, tx %v, output %v, tao %+v", err, txid, i, tao)
|
glog.Errorf("tai.Addresses error %v, tx %v, output %v, tao %+v", err, txid, i, tao)
|
||||||
@ -403,11 +403,11 @@ func (w *Worker) txFromTxAddress(txid string, ta *db.TxAddresses, bi *db.BlockIn
|
|||||||
Blockheight: int(ta.Height),
|
Blockheight: int(ta.Height),
|
||||||
Blocktime: bi.Time,
|
Blocktime: bi.Time,
|
||||||
Confirmations: bestheight - ta.Height + 1,
|
Confirmations: bestheight - ta.Height + 1,
|
||||||
Fees: w.chainParser.AmountToDecimalString(&feesSat),
|
FeesSat: (*Amount)(&feesSat),
|
||||||
Time: bi.Time,
|
Time: bi.Time,
|
||||||
Txid: txid,
|
Txid: txid,
|
||||||
ValueIn: w.chainParser.AmountToDecimalString(&valInSat),
|
ValueInSat: (*Amount)(&valInSat),
|
||||||
ValueOut: w.chainParser.AmountToDecimalString(&valOutSat),
|
ValueOutSat: (*Amount)(&valOutSat),
|
||||||
Vin: vins,
|
Vin: vins,
|
||||||
Vout: vouts,
|
Vout: vouts,
|
||||||
}
|
}
|
||||||
@ -486,14 +486,8 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
|
|||||||
} else {
|
} else {
|
||||||
b = nil
|
b = nil
|
||||||
}
|
}
|
||||||
var balance, balanceSat string
|
|
||||||
if b != nil {
|
|
||||||
balance = bchain.AmountToDecimalString(b, ci.Decimals)
|
|
||||||
balanceSat = b.String()
|
|
||||||
}
|
|
||||||
erc20t[i] = Erc20Token{
|
erc20t[i] = Erc20Token{
|
||||||
Balance: balance,
|
BalanceSat: (*Amount)(b),
|
||||||
BalanceSat: balanceSat,
|
|
||||||
Contract: ci.Contract,
|
Contract: ci.Contract,
|
||||||
Name: ci.Name,
|
Name: ci.Name,
|
||||||
Symbol: ci.Symbol,
|
Symbol: ci.Symbol,
|
||||||
@ -522,15 +516,16 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option GetA
|
|||||||
return nil, NewAPIError(fmt.Sprintf("Invalid address, %v", err), true)
|
return nil, NewAPIError(fmt.Sprintf("Invalid address, %v", err), true)
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
ba *db.AddrBalance
|
ba *db.AddrBalance
|
||||||
erc20t []Erc20Token
|
erc20t []Erc20Token
|
||||||
erc20c *bchain.Erc20Contract
|
erc20c *bchain.Erc20Contract
|
||||||
txm []string
|
txm []string
|
||||||
txs []*Tx
|
txs []*Tx
|
||||||
txids []string
|
txids []string
|
||||||
pg Paging
|
pg Paging
|
||||||
uBalSat big.Int
|
uBalSat big.Int
|
||||||
totalReceived, totalSent, nonce string
|
totalReceived, totalSent *big.Int
|
||||||
|
nonce string
|
||||||
)
|
)
|
||||||
if w.chainType == bchain.ChainEthereumType {
|
if w.chainType == bchain.ChainEthereumType {
|
||||||
var n uint64
|
var n uint64
|
||||||
@ -646,19 +641,17 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option GetA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if w.chainType == bchain.ChainBitcoinType {
|
if w.chainType == bchain.ChainBitcoinType {
|
||||||
totalReceived = w.chainParser.AmountToDecimalString(ba.ReceivedSat())
|
totalReceived = ba.ReceivedSat()
|
||||||
totalSent = w.chainParser.AmountToDecimalString(&ba.SentSat)
|
totalSent = &ba.SentSat
|
||||||
}
|
}
|
||||||
r := &Address{
|
r := &Address{
|
||||||
Paging: pg,
|
Paging: pg,
|
||||||
AddrStr: address,
|
AddrStr: address,
|
||||||
Balance: w.chainParser.AmountToDecimalString(&ba.BalanceSat),
|
BalanceSat: (*Amount)(&ba.BalanceSat),
|
||||||
BalanceSat: ba.BalanceSat.String(),
|
TotalReceivedSat: (*Amount)(totalReceived),
|
||||||
TotalReceived: totalReceived,
|
TotalSentSat: (*Amount)(totalSent),
|
||||||
TotalSent: totalSent,
|
|
||||||
TxApperances: int(ba.Txs),
|
TxApperances: int(ba.Txs),
|
||||||
UnconfirmedBalance: w.chainParser.AmountToDecimalString(&uBalSat),
|
UnconfirmedBalanceSat: (*Amount)(&uBalSat),
|
||||||
UnconfirmedBalanceSat: uBalSat.String(),
|
|
||||||
UnconfirmedTxApperances: len(txm),
|
UnconfirmedTxApperances: len(txm),
|
||||||
Transactions: txs,
|
Transactions: txs,
|
||||||
Txids: txids,
|
Txids: txids,
|
||||||
@ -714,8 +707,7 @@ func (w *Worker) GetAddressUtxo(address string, onlyConfirmed bool) ([]AddressUt
|
|||||||
r = append(r, AddressUtxo{
|
r = append(r, AddressUtxo{
|
||||||
Txid: bchainTx.Txid,
|
Txid: bchainTx.Txid,
|
||||||
Vout: int32(i),
|
Vout: int32(i),
|
||||||
AmountSat: vout.ValueSat,
|
AmountSat: (*Amount)(&vout.ValueSat),
|
||||||
Amount: w.chainParser.AmountToDecimalString(&vout.ValueSat),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -734,7 +726,7 @@ func (w *Worker) GetAddressUtxo(address string, onlyConfirmed bool) ([]AddressUt
|
|||||||
outpoints := make([]bchain.Outpoint, 0, 8)
|
outpoints := make([]bchain.Outpoint, 0, 8)
|
||||||
err = w.db.GetAddrDescTransactions(addrDesc, 0, ^uint32(0), func(txid string, vout int32, isOutput bool) error {
|
err = w.db.GetAddrDescTransactions(addrDesc, 0, ^uint32(0), func(txid string, vout int32, isOutput bool) error {
|
||||||
if isOutput {
|
if isOutput {
|
||||||
outpoints = append(outpoints, bchain.Outpoint{txid, vout})
|
outpoints = append(outpoints, bchain.Outpoint{Txid: txid, Vout: vout})
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@ -772,8 +764,7 @@ func (w *Worker) GetAddressUtxo(address string, onlyConfirmed bool) ([]AddressUt
|
|||||||
r = append(r, AddressUtxo{
|
r = append(r, AddressUtxo{
|
||||||
Txid: o.Txid,
|
Txid: o.Txid,
|
||||||
Vout: o.Vout,
|
Vout: o.Vout,
|
||||||
AmountSat: v,
|
AmountSat: (*Amount)(&v),
|
||||||
Amount: w.chainParser.AmountToDecimalString(&v),
|
|
||||||
Height: int(ta.Height),
|
Height: int(ta.Height),
|
||||||
Confirmations: bestheight - int(ta.Height) + 1,
|
Confirmations: bestheight - int(ta.Height) + 1,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -414,12 +414,11 @@ func GetErc20FromTx(tx *bchain.Tx) ([]Erc20Transfer, error) {
|
|||||||
|
|
||||||
// EthereumTxData contains ethereum specific transaction data
|
// EthereumTxData contains ethereum specific transaction data
|
||||||
type EthereumTxData struct {
|
type EthereumTxData struct {
|
||||||
Status int `json:"status"` // 1 OK, 0 Fail, -1 pending
|
Status int `json:"status"` // 1 OK, 0 Fail, -1 pending
|
||||||
Nonce uint64 `json:"nonce"`
|
Nonce uint64 `json:"nonce"`
|
||||||
GasLimit *big.Int `json:"gaslimit"`
|
GasLimit *big.Int `json:"gaslimit"`
|
||||||
GasUsed *big.Int `json:"gasused"`
|
GasUsed *big.Int `json:"gasused"`
|
||||||
GasPrice string `json:"gasprice"`
|
GasPrice *big.Int `json:"gasprice"`
|
||||||
GasPriceNum *big.Int `json:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEthereumTxData returns EthereumTxData from bchain.Tx
|
// GetEthereumTxData returns EthereumTxData from bchain.Tx
|
||||||
@ -430,8 +429,7 @@ func GetEthereumTxData(tx *bchain.Tx) *EthereumTxData {
|
|||||||
if csd.Tx != nil {
|
if csd.Tx != nil {
|
||||||
etd.Nonce, _ = hexutil.DecodeUint64(csd.Tx.AccountNonce)
|
etd.Nonce, _ = hexutil.DecodeUint64(csd.Tx.AccountNonce)
|
||||||
etd.GasLimit, _ = hexutil.DecodeBig(csd.Tx.GasLimit)
|
etd.GasLimit, _ = hexutil.DecodeBig(csd.Tx.GasLimit)
|
||||||
etd.GasPriceNum, _ = hexutil.DecodeBig(csd.Tx.GasPrice)
|
etd.GasPrice, _ = hexutil.DecodeBig(csd.Tx.GasPrice)
|
||||||
etd.GasPrice = bchain.AmountToDecimalString(etd.GasPriceNum, EtherAmountDecimalPoint)
|
|
||||||
}
|
}
|
||||||
if csd.Receipt != nil {
|
if csd.Receipt != nil {
|
||||||
if csd.Receipt.Status == "0x1" {
|
if csd.Receipt.Status == "0x1" {
|
||||||
|
|||||||
@ -369,11 +369,12 @@ type TemplateData struct {
|
|||||||
|
|
||||||
func (s *PublicServer) parseTemplates() []*template.Template {
|
func (s *PublicServer) parseTemplates() []*template.Template {
|
||||||
templateFuncMap := template.FuncMap{
|
templateFuncMap := template.FuncMap{
|
||||||
"formatTime": formatTime,
|
"formatTime": formatTime,
|
||||||
"formatUnixTime": formatUnixTime,
|
"formatUnixTime": formatUnixTime,
|
||||||
"formatAmount": formatAmount,
|
"formatAmount": s.formatAmount,
|
||||||
"setTxToTemplateData": setTxToTemplateData,
|
"formatAmountWithDecimals": formatAmountWithDecimals,
|
||||||
"stringInSlice": stringInSlice,
|
"setTxToTemplateData": setTxToTemplateData,
|
||||||
|
"stringInSlice": stringInSlice,
|
||||||
}
|
}
|
||||||
t := make([]*template.Template, tplCount)
|
t := make([]*template.Template, tplCount)
|
||||||
t[errorTpl] = template.Must(template.New("error").Funcs(templateFuncMap).ParseFiles("./static/templates/error.html", "./static/templates/base.html"))
|
t[errorTpl] = template.Must(template.New("error").Funcs(templateFuncMap).ParseFiles("./static/templates/error.html", "./static/templates/base.html"))
|
||||||
@ -403,11 +404,18 @@ func formatTime(t time.Time) string {
|
|||||||
|
|
||||||
// for now return the string as it is
|
// for now return the string as it is
|
||||||
// in future could be used to do coin specific formatting
|
// in future could be used to do coin specific formatting
|
||||||
func formatAmount(a string) string {
|
func (s *PublicServer) formatAmount(a *api.Amount) string {
|
||||||
if a == "" {
|
if a == nil {
|
||||||
return "0"
|
return "0"
|
||||||
}
|
}
|
||||||
return a
|
return s.chainParser.AmountToDecimalString((*big.Int)(a))
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatAmountWithDecimals(a *api.Amount, d int) string {
|
||||||
|
if a == nil {
|
||||||
|
return "0"
|
||||||
|
}
|
||||||
|
return bchain.AmountToDecimalString((*big.Int)(a), d)
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from template to support txdetail.html functionality
|
// called from template to support txdetail.html functionality
|
||||||
|
|||||||
@ -312,7 +312,7 @@ func txToResTx(tx *api.Tx) resTx {
|
|||||||
Script: &script,
|
Script: &script,
|
||||||
Sequence: int64(vin.Sequence),
|
Sequence: int64(vin.Sequence),
|
||||||
OutputIndex: int(vin.Vout),
|
OutputIndex: int(vin.Vout),
|
||||||
Satoshis: vin.ValueSat.Int64(),
|
Satoshis: (*big.Int)(vin.ValueSat).Int64(),
|
||||||
}
|
}
|
||||||
if len(vin.Addresses) > 0 {
|
if len(vin.Addresses) > 0 {
|
||||||
a := vin.Addresses[0]
|
a := vin.Addresses[0]
|
||||||
@ -325,7 +325,7 @@ func txToResTx(tx *api.Tx) resTx {
|
|||||||
vout := &tx.Vout[i]
|
vout := &tx.Vout[i]
|
||||||
script := vout.ScriptPubKey.Hex
|
script := vout.ScriptPubKey.Hex
|
||||||
output := txOutputs{
|
output := txOutputs{
|
||||||
Satoshis: vout.ValueSat.Int64(),
|
Satoshis: (*big.Int)(vout.ValueSat).Int64(),
|
||||||
Script: &script,
|
Script: &script,
|
||||||
}
|
}
|
||||||
if len(vout.ScriptPubKey.Addresses) > 0 {
|
if len(vout.ScriptPubKey.Addresses) > 0 {
|
||||||
@ -342,15 +342,15 @@ func txToResTx(tx *api.Tx) resTx {
|
|||||||
}
|
}
|
||||||
return resTx{
|
return resTx{
|
||||||
BlockTimestamp: tx.Blocktime,
|
BlockTimestamp: tx.Blocktime,
|
||||||
FeeSatoshis: tx.FeesSat.Int64(),
|
FeeSatoshis: (*big.Int)(tx.FeesSat).Int64(),
|
||||||
Hash: tx.Txid,
|
Hash: tx.Txid,
|
||||||
Height: h,
|
Height: h,
|
||||||
Hex: tx.Hex,
|
Hex: tx.Hex,
|
||||||
Inputs: inputs,
|
Inputs: inputs,
|
||||||
InputSatoshis: tx.ValueInSat.Int64(),
|
InputSatoshis: (*big.Int)(tx.ValueInSat).Int64(),
|
||||||
Locktime: int(tx.Locktime),
|
Locktime: int(tx.Locktime),
|
||||||
Outputs: outputs,
|
Outputs: outputs,
|
||||||
OutputSatoshis: tx.ValueOutSat.Int64(),
|
OutputSatoshis: (*big.Int)(tx.ValueOutSat).Int64(),
|
||||||
Version: int(tx.Version),
|
Version: int(tx.Version),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -407,7 +407,7 @@ func (s *SocketIoServer) getAddressHistory(addr []string, opts *addrOpts) (res r
|
|||||||
ads[a] = hi
|
ads[a] = hi
|
||||||
}
|
}
|
||||||
hi.InputIndexes = append(hi.InputIndexes, int(vin.N))
|
hi.InputIndexes = append(hi.InputIndexes, int(vin.N))
|
||||||
totalSat.Sub(&totalSat, &vin.ValueSat)
|
totalSat.Sub(&totalSat, (*big.Int)(vin.ValueSat))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := range tx.Vout {
|
for i := range tx.Vout {
|
||||||
@ -420,7 +420,7 @@ func (s *SocketIoServer) getAddressHistory(addr []string, opts *addrOpts) (res r
|
|||||||
ads[a] = hi
|
ads[a] = hi
|
||||||
}
|
}
|
||||||
hi.OutputIndexes = append(hi.OutputIndexes, int(vout.N))
|
hi.OutputIndexes = append(hi.OutputIndexes, int(vout.N))
|
||||||
totalSat.Add(&totalSat, &vout.ValueSat)
|
totalSat.Add(&totalSat, (*big.Int)(vout.ValueSat))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ahi := addressHistoryItem{}
|
ahi := addressHistoryItem{}
|
||||||
|
|||||||
@ -91,7 +91,7 @@ func NewWebsocketServer(db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxC
|
|||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow all origins, at least for now
|
// allow all origins
|
||||||
func checkOrigin(r *http.Request) bool {
|
func checkOrigin(r *http.Request) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{{define "specific"}}{{$cs := .CoinShortcut}}{{$addr := .Address}}{{$data := .}}
|
{{define "specific"}}{{$cs := .CoinShortcut}}{{$addr := .Address}}{{$data := .}}
|
||||||
<h1>{{if $addr.Erc20Contract}}Contract {{$addr.Erc20Contract.Name}} ({{$addr.Erc20Contract.Symbol}}){{else}}Address{{end}}
|
<h1>{{if $addr.Erc20Contract}}Contract {{$addr.Erc20Contract.Name}} ({{$addr.Erc20Contract.Symbol}}){{else}}Address{{end}}
|
||||||
<small class="text-muted">{{formatAmount $addr.Balance}} {{$cs}}</small>
|
<small class="text-muted">{{formatAmount $addr.BalanceSat}} {{$cs}}</small>
|
||||||
</h1>
|
</h1>
|
||||||
<div class="alert alert-data ellipsis">
|
<div class="alert alert-data ellipsis">
|
||||||
<span class="data">{{$addr.AddrStr}}</span>
|
<span class="data">{{$addr.AddrStr}}</span>
|
||||||
@ -13,7 +13,7 @@
|
|||||||
{{- if eq .ChainType 1 -}}
|
{{- if eq .ChainType 1 -}}
|
||||||
<tr>
|
<tr>
|
||||||
<td style="width: 25%;">Balance</td>
|
<td style="width: 25%;">Balance</td>
|
||||||
<td class="data">{{formatAmount $addr.Balance}} {{$cs}}</td>
|
<td class="data">{{formatAmount $addr.BalanceSat}} {{$cs}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Non-contract Transactions</td>
|
<td>Non-contract Transactions</td>
|
||||||
@ -37,7 +37,7 @@
|
|||||||
{{- range $et := $addr.Erc20Tokens -}}
|
{{- range $et := $addr.Erc20Tokens -}}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="data ellipsis"><a href="/address/{{$et.Contract}}">{{$et.Name}}</a></td>
|
<td class="data ellipsis"><a href="/address/{{$et.Contract}}">{{$et.Name}}</a></td>
|
||||||
<td class="data">{{formatAmount $et.Balance}} {{$et.Symbol}}</td>
|
<td class="data">{{formatAmountWithDecimals $et.BalanceSat $et.Decimals}} {{$et.Symbol}}</td>
|
||||||
<td class="data">{{$et.Txs}}</td>
|
<td class="data">{{$et.Txs}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
@ -50,15 +50,15 @@
|
|||||||
{{- else -}}
|
{{- else -}}
|
||||||
<tr>
|
<tr>
|
||||||
<td style="width: 25%;">Total Received</td>
|
<td style="width: 25%;">Total Received</td>
|
||||||
<td class="data">{{formatAmount $addr.TotalReceived}} {{$cs}}</td>
|
<td class="data">{{formatAmount $addr.TotalReceivedSat}} {{$cs}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Total Sent</td>
|
<td>Total Sent</td>
|
||||||
<td class="data">{{formatAmount $addr.TotalSent}} {{$cs}}</td>
|
<td class="data">{{formatAmount $addr.TotalSentSat}} {{$cs}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Final Balance</td>
|
<td>Final Balance</td>
|
||||||
<td class="data">{{formatAmount $addr.Balance}} {{$cs}}</td>
|
<td class="data">{{formatAmount $addr.BalanceSat}} {{$cs}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>No. Transactions</td>
|
<td>No. Transactions</td>
|
||||||
@ -83,7 +83,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td style="width: 25%;">Unconfirmed Balance</td>
|
<td style="width: 25%;">Unconfirmed Balance</td>
|
||||||
<td class="data">{{formatAmount $addr.UnconfirmedBalance}} {{$cs}}</td>
|
<td class="data">{{formatAmount $addr.UnconfirmedBalanceSat}} {{$cs}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>No. Transactions</td>
|
<td>No. Transactions</td>
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Value</td>
|
<td>Value</td>
|
||||||
<td class="data">{{formatAmount $tx.ValueOut}} {{$cs}}</td>
|
<td class="data">{{formatAmount $tx.ValueOutSat}} {{$cs}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Gas Used / Limit</td>
|
<td>Gas Used / Limit</td>
|
||||||
@ -49,17 +49,17 @@
|
|||||||
{{- else -}}
|
{{- else -}}
|
||||||
<tr>
|
<tr>
|
||||||
<td>Total Input</td>
|
<td>Total Input</td>
|
||||||
<td class="data">{{formatAmount $tx.ValueIn}} {{$cs}}</td>
|
<td class="data">{{formatAmount $tx.ValueInSat}} {{$cs}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Total Output</td>
|
<td>Total Output</td>
|
||||||
<td class="data">{{formatAmount $tx.ValueOut}} {{$cs}}</td>
|
<td class="data">{{formatAmount $tx.ValueOutSat}} {{$cs}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- if $tx.Fees -}}
|
{{- if $tx.FeesSat -}}
|
||||||
<tr>
|
<tr>
|
||||||
<td>Fees</td>
|
<td>Fees</td>
|
||||||
<td class="data">{{formatAmount $tx.Fees}} {{$cs}}</td>
|
<td class="data">{{formatAmount $tx.FeesSat}} {{$cs}}</td>
|
||||||
</tr>{{end -}}
|
</tr>{{end -}}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@ -26,7 +26,7 @@
|
|||||||
{{- else -}}
|
{{- else -}}
|
||||||
<span class="float-left">{{- if $vin.ScriptSig.Hex -}}Unparsed address{{- else -}}No Inputs (Newly Generated Coins){{- end -}}</span>
|
<span class="float-left">{{- if $vin.ScriptSig.Hex -}}Unparsed address{{- else -}}No Inputs (Newly Generated Coins){{- end -}}</span>
|
||||||
{{- end -}}{{- if $vin.Addresses -}}
|
{{- end -}}{{- if $vin.Addresses -}}
|
||||||
<span class="float-right{{if stringInSlice $addr $vin.Addresses}} text-danger{{end}}">{{formatAmount $vin.Value}} {{$cs}}</span>
|
<span class="float-right{{if stringInSlice $addr $vin.Addresses}} text-danger{{end}}">{{formatAmount $vin.ValueSat}} {{$cs}}</span>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -59,7 +59,7 @@
|
|||||||
<span class="float-left">Unparsed address</span>
|
<span class="float-left">Unparsed address</span>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
<span class="float-right{{if stringInSlice $addr $vout.ScriptPubKey.Addresses}} text-success{{end}}">
|
<span class="float-right{{if stringInSlice $addr $vout.ScriptPubKey.Addresses}} text-success{{end}}">
|
||||||
{{formatAmount $vout.Value}} {{$cs}} {{if $vout.Spent}}<a class="text-danger" href="{{if $vout.SpentTxID}}/tx/{{$vout.SpentTxID}}{{else}}/spending/{{$tx.Txid}}/{{$vout.N}}{{end}}" title="Spent">➡</a>{{else -}}
|
{{formatAmount $vout.ValueSat}} {{$cs}} {{if $vout.Spent}}<a class="text-danger" href="{{if $vout.SpentTxID}}/tx/{{$vout.SpentTxID}}{{else}}/spending/{{$tx.Txid}}/{{$vout.N}}{{end}}" title="Spent">➡</a>{{else -}}
|
||||||
<span class="text-success" title="Unspent"> <b>×</b></span>
|
<span class="text-success" title="Unspent"> <b>×</b></span>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
</span>
|
</span>
|
||||||
@ -77,8 +77,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row line-top">
|
<div class="row line-top">
|
||||||
<div class="col-xs-6 col-sm-4 col-md-4">
|
<div class="col-xs-6 col-sm-4 col-md-4">
|
||||||
{{- if $tx.Fees -}}
|
{{- if $tx.FeesSat -}}
|
||||||
<span class="txvalues txvalues-default">Fee: {{formatAmount $tx.Fees}} {{$cs}}</span>
|
<span class="txvalues txvalues-default">Fee: {{formatAmount $tx.FeesSat}} {{$cs}}</span>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-6 col-sm-8 col-md-8 text-right">
|
<div class="col-xs-6 col-sm-8 col-md-8 text-right">
|
||||||
@ -87,7 +87,7 @@
|
|||||||
{{- else -}}
|
{{- else -}}
|
||||||
<span class="txvalues txvalues-danger ng-hide">Unconfirmed Transaction!</span>
|
<span class="txvalues txvalues-danger ng-hide">Unconfirmed Transaction!</span>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
<span class="txvalues txvalues-primary">{{formatAmount $tx.ValueOut}} {{$cs}}</span>
|
<span class="txvalues txvalues-primary">{{formatAmount $tx.ValueOutSat}} {{$cs}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -66,7 +66,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3 text-right" style="padding: .4rem 0;">
|
<div class="col-md-3 text-right" style="padding: .4rem 0;">
|
||||||
{{formatAmount $tx.ValueOut}} {{$cs}}
|
{{formatAmount $tx.ValueOutSat}} {{$cs}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{- if $tx.Erc20Transfers -}}
|
{{- if $tx.Erc20Transfers -}}
|
||||||
@ -106,15 +106,15 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3 text-right" style="padding: .4rem 0;">{{formatAmount $erc20.Tokens}} {{$erc20.Symbol}}</div>
|
<div class="col-md-3 text-right" style="padding: .4rem 0;">{{formatAmountWithDecimals $erc20.Tokens $erc20.Decimals}} {{$erc20.Symbol}}</div>
|
||||||
</div>
|
</div>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
<div class="row" style="padding: 6px 15px;"></div>
|
<div class="row" style="padding: 6px 15px;"></div>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
<div class="row line-top">
|
<div class="row line-top">
|
||||||
<div class="col-xs-6 col-sm-4 col-md-4">
|
<div class="col-xs-6 col-sm-4 col-md-4">
|
||||||
{{- if $tx.Fees -}}
|
{{- if $tx.FeesSat -}}
|
||||||
<span class="txvalues txvalues-default">Fee: {{formatAmount $tx.Fees}} {{$cs}}</span>
|
<span class="txvalues txvalues-default">Fee: {{formatAmount $tx.FeesSat}} {{$cs}}</span>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-6 col-sm-8 col-md-8 text-right">
|
<div class="col-xs-6 col-sm-8 col-md-8 text-right">
|
||||||
@ -123,7 +123,7 @@
|
|||||||
{{- else -}}
|
{{- else -}}
|
||||||
<span class="txvalues txvalues-danger ng-hide">Unconfirmed Transaction!</span>
|
<span class="txvalues txvalues-danger ng-hide">Unconfirmed Transaction!</span>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
<span class="txvalues txvalues-primary">{{formatAmount $tx.ValueOut}} {{$cs}}</span>
|
<span class="txvalues txvalues-primary">{{formatAmount $tx.ValueOutSat}} {{$cs}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user