refactor connect/disconnect asset
parent
7e5cbeff84
commit
ce3c77632c
|
@ -96,7 +96,6 @@ type Vout struct {
|
|||
// Contains SyscoinSpecific asset information hex decoded and pertinent to API display
|
||||
type AssetSpecific struct {
|
||||
AssetGuid uint32 `json:"assetGuid"`
|
||||
AddrStr string `json:"addrStr,omitempty"`
|
||||
Contract string `json:"contract,omitempty"`
|
||||
Symbol string `json:"symbol"`
|
||||
PubData map[string]interface{} `json:"pubData"`
|
||||
|
@ -115,7 +114,6 @@ type AssetSpecific struct {
|
|||
// Contains SyscoinSpecific assets information when searching for assets
|
||||
type AssetsSpecific struct {
|
||||
AssetGuid uint32 `json:"assetGuid"`
|
||||
AddrStr string `json:"addrStr,omitempty"`
|
||||
Contract string `json:"contract"`
|
||||
Symbol string `json:"symbol"`
|
||||
PubData map[string]interface{} `json:"pubData"`
|
||||
|
|
|
@ -1097,34 +1097,11 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option Acco
|
|||
}
|
||||
if ba.AssetBalances != nil && option > AccountDetailsBasic {
|
||||
tokens = make(bchain.Tokens, 0, len(ba.AssetBalances)+1)
|
||||
var ownerFound bool = false
|
||||
for k, v := range ba.AssetBalances {
|
||||
dbAsset, errAsset := w.db.GetAsset(uint32(k), nil)
|
||||
if errAsset != nil || dbAsset == nil {
|
||||
return nil, errAsset
|
||||
}
|
||||
if !ownerFound {
|
||||
// add token as unallocated if address matches asset owner address
|
||||
if bytes.Equal(addrDesc, dbAsset.AddrDesc) {
|
||||
ownerBalance := big.NewInt(dbAsset.AssetObj.Balance)
|
||||
totalOwnerAssetReceived := bchain.ReceivedSatFromBalances(ownerBalance, v.SentSat)
|
||||
assetGuid := strconv.FormatUint(uint64(k), 10)
|
||||
tokens = append(tokens, &bchain.Token{
|
||||
Type: bchain.SPTUnallocatedTokenType,
|
||||
AddrStr: dbAsset.AddrDesc.String(),
|
||||
Name: assetGuid + " (" + dbAsset.AssetObj.Symbol + ")",
|
||||
Decimals: int(dbAsset.AssetObj.Precision),
|
||||
Symbol: dbAsset.AssetObj.Symbol,
|
||||
BalanceSat: (*bchain.Amount)(ownerBalance),
|
||||
TotalReceivedSat: (*bchain.Amount)(totalOwnerAssetReceived),
|
||||
TotalSentSat: (*bchain.Amount)(v.SentSat),
|
||||
Contract: assetGuid,
|
||||
Transfers: v.Transfers,
|
||||
ContractIndex: assetGuid,
|
||||
})
|
||||
ownerFound = true
|
||||
}
|
||||
}
|
||||
totalAssetReceived := bchain.ReceivedSatFromBalances(v.BalanceSat, v.SentSat)
|
||||
assetGuid := strconv.FormatUint(uint64(k), 10)
|
||||
tokens = append(tokens, &bchain.Token{
|
||||
|
@ -1307,7 +1284,6 @@ func (w *Worker) GetAsset(asset string, page int, txsOnPage int, option AccountD
|
|||
AssetDetails: &AssetSpecific{
|
||||
AssetGuid: assetGuid,
|
||||
Symbol: dbAsset.AssetObj.Symbol,
|
||||
AddrStr: dbAsset.AddrDesc.String(),
|
||||
Contract: "0x" + hex.EncodeToString(dbAsset.AssetObj.Contract),
|
||||
Balance: (*bchain.Amount)(big.NewInt(dbAsset.AssetObj.Balance)),
|
||||
TotalSupply: (*bchain.Amount)(big.NewInt(dbAsset.AssetObj.TotalSupply)),
|
||||
|
@ -1734,7 +1710,6 @@ func (w *Worker) GetAddressUtxo(address string, onlyConfirmed bool) (Utxos, erro
|
|||
assetDetails := &AssetSpecific{
|
||||
AssetGuid: a.AssetInfo.AssetGuid,
|
||||
Symbol: dbAsset.AssetObj.Symbol,
|
||||
AddrStr: dbAsset.AddrDesc.String(),
|
||||
Contract: "0x" + hex.EncodeToString(dbAsset.AssetObj.Contract),
|
||||
Balance: (*bchain.Amount)(big.NewInt(dbAsset.AssetObj.Balance)),
|
||||
TotalSupply: (*bchain.Amount)(big.NewInt(dbAsset.AssetObj.TotalSupply)),
|
||||
|
|
32
api/xpub.go
32
api/xpub.go
|
@ -241,11 +241,9 @@ func (w *Worker) tokenFromXpubAddress(data *xpubData, ad *xpubAddress, changeInd
|
|||
a, _, _ := w.chainParser.GetAddressesFromAddrDesc(ad.addrDesc)
|
||||
numAssetBalances := 0
|
||||
if ad.balance != nil {
|
||||
// + 1 for owner asset for unallocated token
|
||||
numAssetBalances = 1 + len(ad.balance.AssetBalances)
|
||||
numAssetBalances = len(ad.balance.AssetBalances)
|
||||
}
|
||||
// +1 for base token always appended
|
||||
tokens := make(bchain.Tokens, 0, 1+numAssetBalances)
|
||||
tokens := make(bchain.Tokens, 0, numAssetBalances)
|
||||
var address string
|
||||
if len(a) > 0 {
|
||||
address = a[0]
|
||||
|
@ -258,37 +256,12 @@ func (w *Worker) tokenFromXpubAddress(data *xpubData, ad *xpubAddress, changeInd
|
|||
balance = &ad.balance.BalanceSat
|
||||
totalSent = &ad.balance.SentSat
|
||||
totalReceived = ad.balance.ReceivedSat()
|
||||
// for asset tokens
|
||||
var ownerFound bool = false
|
||||
for k, v := range ad.balance.AssetBalances {
|
||||
dbAsset, errAsset := w.db.GetAsset(k, nil)
|
||||
if errAsset != nil || dbAsset == nil {
|
||||
return nil, errAsset
|
||||
}
|
||||
if !ownerFound {
|
||||
// add token as unallocated if address matches asset owner address
|
||||
if bytes.Equal(ad.addrDesc, dbAsset.AddrDesc) {
|
||||
ownerBalance := big.NewInt(dbAsset.AssetObj.Balance)
|
||||
totalOwnerAssetReceived := bchain.ReceivedSatFromBalances(ownerBalance, v.SentSat)
|
||||
assetGuid := strconv.FormatUint(uint64(k), 10)
|
||||
tokens = append(tokens, &bchain.Token{
|
||||
Type: bchain.SPTUnallocatedTokenType,
|
||||
Name: address,
|
||||
Decimals: int(dbAsset.AssetObj.Precision),
|
||||
Symbol: dbAsset.AssetObj.Symbol,
|
||||
BalanceSat: (*bchain.Amount)(ownerBalance),
|
||||
TotalReceivedSat: (*bchain.Amount)(totalOwnerAssetReceived),
|
||||
TotalSentSat: (*bchain.Amount)(v.SentSat),
|
||||
Path: fmt.Sprintf("%s/%d/%d", data.basePath, changeIndex, index),
|
||||
Contract: assetGuid,
|
||||
Transfers: v.Transfers,
|
||||
ContractIndex: assetGuid,
|
||||
})
|
||||
ownerFound = true
|
||||
}
|
||||
}
|
||||
totalAssetReceived := bchain.ReceivedSatFromBalances(v.BalanceSat, v.SentSat)
|
||||
// add token as unallocated if address matches asset owner address other wise its allocated
|
||||
assetGuid := strconv.FormatUint(uint64(k), 10)
|
||||
tokens = append(tokens, &bchain.Token{
|
||||
Type: bchain.SPTTokenType,
|
||||
|
@ -710,7 +683,6 @@ func (w *Worker) GetXpubUtxo(xpub string, onlyConfirmed bool, gap int) (Utxos, e
|
|||
assetDetails := &AssetSpecific{
|
||||
AssetGuid: a.AssetInfo.AssetGuid,
|
||||
Symbol: dbAsset.AssetObj.Symbol,
|
||||
AddrStr: dbAsset.AddrDesc.String(),
|
||||
Contract: "0x" + hex.EncodeToString(dbAsset.AssetObj.Contract),
|
||||
Balance: (*bchain.Amount)(big.NewInt(dbAsset.AssetObj.Balance)),
|
||||
TotalSupply: (*bchain.Amount)(big.NewInt(dbAsset.AssetObj.TotalSupply)),
|
||||
|
|
|
@ -359,6 +359,9 @@ func (p *BaseParser) UnpackAssetTxIndex(buf []byte) []*TxAssetIndex {
|
|||
func (p *BaseParser) GetAssetFromData(sptData []byte) (*Asset, error) {
|
||||
return nil, errors.New("Not supported")
|
||||
}
|
||||
func (p *SyscoinParser) GetAssetFromDesc(addrDesc *bchain.AddressDescriptor) (*bchain.Asset, error) {
|
||||
return nil, errors.New("Not supported")
|
||||
}
|
||||
func (p *BaseParser) GetAllocationFromTx(tx *Tx) (*AssetAllocation, error) {
|
||||
return nil, errors.New("Not supported")
|
||||
}
|
||||
|
|
|
@ -279,6 +279,25 @@ func (p *SyscoinParser) GetAllocationFromTx(tx *bchain.Tx) (*bchain.AssetAllocat
|
|||
return &assetAllocation, nil
|
||||
}
|
||||
|
||||
func (p *SyscoinParser) GetAssetFromDesc(addrDesc *bchain.AddressDescriptor) (*bchain.Asset, error) {
|
||||
script, err := p.GetScriptFromAddrDesc(addrDesc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sptData := p.TryGetOPReturn(script)
|
||||
if sptData == nil {
|
||||
return nil, errors.New("OP_RETURN empty")
|
||||
}
|
||||
|
||||
var asset bchain.Asset
|
||||
r := bytes.NewReader(sptData)
|
||||
err := asset.AssetObj.Deserialize(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &asset, nil
|
||||
}
|
||||
|
||||
func (p *SyscoinParser) GetAssetFromData(sptData []byte) (*bchain.Asset, error) {
|
||||
var asset bchain.Asset
|
||||
r := bytes.NewReader(sptData)
|
||||
|
|
|
@ -450,7 +450,6 @@ const XPUBAddressTokenType TokenType = "XPUBAddress"
|
|||
// Syscoin SPT transaction
|
||||
const SPTNoneType TokenType = "Syscoin"
|
||||
const SPTTokenType TokenType = "SPTAllocated"
|
||||
const SPTUnallocatedTokenType TokenType = "SPTUnallocated"
|
||||
const SPTUnknownType TokenType = "SPTUnknown"
|
||||
const SPTAssetActivateType TokenType = "SPTAssetActivate"
|
||||
const SPTAssetUpdateType TokenType = "SPTAssetUpdate"
|
||||
|
@ -520,7 +519,6 @@ type AssetAllocation struct {
|
|||
type Asset struct {
|
||||
Transactions uint32
|
||||
AssetObj wire.AssetType
|
||||
AddrDesc AddressDescriptor
|
||||
}
|
||||
// Assets is array of Asset
|
||||
type Assets []Asset
|
||||
|
@ -762,6 +760,7 @@ type BlockChainParser interface {
|
|||
PackAsset(asset *Asset) ([]byte, error)
|
||||
UnpackAsset(buf []byte) (*Asset, error)
|
||||
GetAssetFromData(sptData []byte) (*Asset, error)
|
||||
GetAssetFromDesc(addrDesc *AddressDescriptor) (*Asset, error)
|
||||
GetAllocationFromTx(tx *Tx) (*AssetAllocation, error)
|
||||
LoadAssets(tx *Tx) error
|
||||
AppendAssetInfo(assetInfo *AssetInfo, buf []byte, varBuf []byte) []byte
|
||||
|
|
|
@ -512,10 +512,8 @@ func (d *RocksDB) processAddressesBitcoinType(block *bchain.Block, addresses bch
|
|||
blockTxAssetAddresses := make(bchain.TxAssetAddressMap)
|
||||
// first process all outputs so that inputs can refer to txs in this block
|
||||
for txi := range block.Txs {
|
||||
var addrDescData *bchain.AddressDescriptor = nil
|
||||
var addrDescOwner *bchain.AddressDescriptor = nil
|
||||
var assetGuid uint32 = 0
|
||||
tx := &block.Txs[txi]
|
||||
var asset *bchain.Asset = nil
|
||||
isActivate := d.chainParser.IsAssetActivateTx(tx.Version)
|
||||
isAssetTx := d.chainParser.IsAssetTx(tx.Version)
|
||||
btxID, err := d.chainParser.PackTxid(tx.Txid)
|
||||
|
@ -593,19 +591,13 @@ func (d *RocksDB) processAddressesBitcoinType(block *bchain.Block, addresses bch
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// replace asset ownership with this addrDesc in ConnectAssetOutput, this should be the change address
|
||||
if isAssetTx && assetGuid == 0 && tao.AssetInfo.ValueSat.Int64() == 0 {
|
||||
assetGuid = tao.AssetInfo.AssetGuid
|
||||
addrDescOwner = &addrDesc
|
||||
}
|
||||
}
|
||||
} else if isAssetTx && addrDesc[0] == txscript.OP_RETURN {
|
||||
// if opreturn save data for later disconnecting output
|
||||
addrDescData = &addrDesc
|
||||
} else if isAssetTx && asset == nil && addrDesc[0] == txscript.OP_RETURN {
|
||||
asset = d.chainParser.GetAssetFromDesc(addrDesc)
|
||||
}
|
||||
}
|
||||
if assetGuid > 0 && addrDescOwner != nil && addrDescData != nil {
|
||||
err := d.ConnectAssetOutput(addrDescData, addrDescOwner, isActivate, isAssetTx, assetGuid, assets)
|
||||
if asset != nil {
|
||||
err := d.ConnectAssetOutput(asset, isActivate, isAssetTx, assets)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1026,7 +1018,6 @@ func (d *RocksDB) disconnectTxAddressesInputs(wb *gorocksdb.WriteBatch, btxID []
|
|||
var err error
|
||||
var addrDesc *bchain.AddressDescriptor = nil
|
||||
isAssetTx := d.chainParser.IsAssetTx(txa.Version)
|
||||
var assetGuid uint32 = 0
|
||||
for i, t := range txa.Inputs {
|
||||
if len(t.AddrDesc) > 0 {
|
||||
input := &inputs[i]
|
||||
|
@ -1081,11 +1072,6 @@ func (d *RocksDB) disconnectTxAddressesInputs(wb *gorocksdb.WriteBatch, btxID []
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// if asset tx save ownership addrDesc for later disconnect when we replace the addrDesc of asset to this one
|
||||
if isAssetTx && assetGuid == 0 && t.AssetInfo.ValueSat.Int64() == 0 {
|
||||
assetGuid = t.AssetInfo.AssetGuid
|
||||
addrDesc = &t.AddrDesc
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ad, _, _ := d.chainParser.GetAddressesFromAddrDesc(t.AddrDesc)
|
||||
|
@ -1094,12 +1080,6 @@ func (d *RocksDB) disconnectTxAddressesInputs(wb *gorocksdb.WriteBatch, btxID []
|
|||
}
|
||||
}
|
||||
}
|
||||
if addrDesc != nil {
|
||||
err := d.DisconnectAssetInput(addrDesc, assets, assetGuid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1110,8 +1090,6 @@ func (d *RocksDB) disconnectTxAddressesOutputs(wb *gorocksdb.WriteBatch, btxID [
|
|||
assets map[uint32]*bchain.Asset, blockTxAssetAddresses bchain.TxAssetAddressMap) error {
|
||||
var addrDesc *bchain.AddressDescriptor = nil
|
||||
isActivate := d.chainParser.IsAssetActivateTx(txa.Version)
|
||||
isAssetTx := d.chainParser.IsAssetTx(txa.Version)
|
||||
var assetGuid uint32 = 0
|
||||
for i, t := range txa.Outputs {
|
||||
if len(t.AddrDesc) > 0 {
|
||||
exist := addressFoundInTx(t.AddrDesc, btxID)
|
||||
|
@ -1142,30 +1120,24 @@ func (d *RocksDB) disconnectTxAddressesOutputs(wb *gorocksdb.WriteBatch, btxID [
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// save it for later
|
||||
if assetGuid == 0 {
|
||||
assetGuid = t.AssetInfo.AssetGuid
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ad, _, _ := d.chainParser.GetAddressesFromAddrDesc(t.AddrDesc)
|
||||
glog.Warningf("Balance for address %s (%s) not found", ad, t.AddrDesc)
|
||||
}
|
||||
} else if isAssetTx && t.AddrDesc[0] == txscript.OP_RETURN {
|
||||
// if opreturn save data for later disconnecting output
|
||||
addrDesc = &t.AddrDesc
|
||||
} else if isAssetTx && asset == nil && t.AddrDesc[0] == txscript.OP_RETURN {
|
||||
asset = d.chainParser.GetAssetFromDesc(&t.AddrDesc)
|
||||
}
|
||||
}
|
||||
}
|
||||
if assetGuid > 0 && addrDesc != nil {
|
||||
err := d.DisconnectAssetOutput(addrDesc, isActivate, assets, assetGuid)
|
||||
if asset != nil {
|
||||
err := d.DisconnectAssetOutput(asset, isActivate, assets)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *RocksDB) disconnectBlock(height uint32, blockTxs []bchain.BlockTxs) error {
|
||||
wb := gorocksdb.NewWriteBatch()
|
||||
defer wb.Destroy()
|
||||
|
|
|
@ -157,20 +157,9 @@ func (d *RocksDB) ConnectAllocationOutput(addrDesc* bchain.AddressDescriptor, he
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *RocksDB) ConnectAssetOutput(addrDescData *bchain.AddressDescriptor, addrDesc *bchain.AddressDescriptor, isActivate bool, isAssetTx bool, assetGuid uint32, assets map[uint32]*bchain.Asset) error {
|
||||
script, err := d.chainParser.GetScriptFromAddrDesc(*addrDescData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sptData := d.chainParser.TryGetOPReturn(script)
|
||||
if sptData == nil {
|
||||
return errors.New("ConnectAssetOutput could not parse opreturn")
|
||||
}
|
||||
asset, err := d.chainParser.GetAssetFromData(sptData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func (d *RocksDB) ConnectAssetOutput(asset *bchain.Asset, isActivate bool, isAssetTx bool, assets map[uint32]*bchain.Asset) error {
|
||||
var dBAsset* bchain.Asset = nil
|
||||
assetGuid := asset.Allocation.VoutAssets[0].AssetGuid
|
||||
if !isActivate {
|
||||
dBAsset, err = d.GetAsset(assetGuid, assets)
|
||||
if err != nil {
|
||||
|
@ -188,7 +177,6 @@ func (d *RocksDB) ConnectAssetOutput(addrDescData *bchain.AddressDescriptor, add
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dBAsset.AddrDesc = *addrDesc
|
||||
}
|
||||
assets[assetGuid] = dBAsset
|
||||
} else {
|
||||
|
@ -226,19 +214,8 @@ func (d *RocksDB) DisconnectAllocationOutput(addrDesc *bchain.AddressDescriptor,
|
|||
assets[assetInfo.AssetGuid] = dBAsset
|
||||
return nil
|
||||
}
|
||||
func (d *RocksDB) DisconnectAssetOutput(addrDesc *bchain.AddressDescriptor, isActivate bool, assets map[uint32]*bchain.Asset, assetGuid uint32) error {
|
||||
script, err := d.chainParser.GetScriptFromAddrDesc(*addrDesc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sptData := d.chainParser.TryGetOPReturn(script)
|
||||
if sptData == nil {
|
||||
return errors.New(fmt.Sprint("DisconnectAssetOutput could not parse opreturn"))
|
||||
}
|
||||
asset, err := d.chainParser.GetAssetFromData(sptData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func (d *RocksDB) DisconnectAssetOutput(asset *bchain.Asset, isActivate bool, assets map[uint32]*bchain.Asset) error {
|
||||
assetGuid := asset.Allocation.VoutAssets[0].AssetGuid
|
||||
dBAsset, err := d.GetAsset(assetGuid, assets)
|
||||
if dBAsset == nil || err != nil {
|
||||
if dBAsset == nil {
|
||||
|
@ -279,18 +256,7 @@ func (d *RocksDB) DisconnectAllocationInput(addrDesc *bchain.AddressDescriptor,
|
|||
assets[assetInfo.AssetGuid] = dBAsset
|
||||
return nil
|
||||
}
|
||||
func (d *RocksDB) DisconnectAssetInput(addrDesc *bchain.AddressDescriptor, assets map[uint32]*bchain.Asset, assetGuid uint32) error {
|
||||
dBAsset, err := d.GetAsset(assetGuid, assets)
|
||||
if dBAsset == nil || err != nil {
|
||||
if dBAsset == nil {
|
||||
return errors.New(fmt.Sprint("DisconnectAssetInput could not read asset " , assetGuid))
|
||||
}
|
||||
return err
|
||||
}
|
||||
dBAsset.AddrDesc = *addrDesc
|
||||
assets[assetGuid] = dBAsset
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *RocksDB) SetupAssetCache() error {
|
||||
start := time.Now()
|
||||
if AssetCache == nil {
|
||||
|
|
|
@ -630,7 +630,6 @@ func (s *SocketIoServer) getAssetHistory(asset string, opts *assetOpts) (res res
|
|||
res.Result.AssetDetails = &api.AssetSpecific{
|
||||
AssetGuid: assetGuid,
|
||||
Symbol: dbAsset.AssetObj.Symbol,
|
||||
AddrStr: dbAsset.AddrDesc.String(),
|
||||
Contract: "0x" + hex.EncodeToString(dbAsset.AssetObj.Contract),
|
||||
Balance: (*bchain.Amount)(big.NewInt(dbAsset.AssetObj.Balance)),
|
||||
TotalSupply: (*bchain.Amount)(big.NewInt(dbAsset.AssetObj.TotalSupply)),
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
<td class="data ellipsis">{{if $t.Contract}}<a href="/asset/{{$t.Contract}}">{{$t.Contract}}</a>{{else}}{{$t.Name}}{{end}}</td>
|
||||
<td class="data ellipsis">{{formatAmountWithDecimals $t.TotalReceivedSat $t.Decimals}} {{$t.Symbol}}</td>
|
||||
<td class="data ellipsis">{{formatAmountWithDecimals $t.TotalSentSat $t.Decimals}} {{$t.Symbol}}</td>
|
||||
<td class="data ellipsis">{{formatAmountWithDecimals $t.BalanceSat $t.Decimals}} {{$t.Symbol}}{{- if eq $t.Type "SPTUnallocated" -}}<span title="Unallocated balance, owned by asset"> ⚠️</span>{{- end -}}</td>
|
||||
<td class="data ellipsis">{{formatAmountWithDecimals $t.BalanceSat $t.Decimals}} {{$t.Symbol}}</td>
|
||||
<td class="data">{{$t.Transfers}}</td>
|
||||
</tr>
|
||||
{{- end -}}{{- end -}}
|
||||
|
|
|
@ -79,8 +79,8 @@
|
|||
{{- range $tokenTransfer := $tx.TokenTransferSummary -}}{{if $tokenTransfer}}
|
||||
<tr>
|
||||
<td class="data ellipsis"><a href="/asset/{{$tokenTransfer.Token}}">{{$tokenTransfer.Token}}</a></td>
|
||||
<td class="data ellipsis">{{formatAmountWithDecimals $tokenTransfer.Value $tokenTransfer.Decimals}} {{$tokenTransfer.Symbol}}{{- if eq $tokenTransfer.Type "SPTUnallocated" -}}<span title="Unallocated balance, owned by asset"> ⚠️</span>{{- end -}}</td>
|
||||
<td class="data ellipsis">{{formatAmountWithDecimals $tokenTransfer.ValueOut $tokenTransfer.Decimals}} {{$tokenTransfer.Symbol}}{{- if eq $tokenTransfer.Type "SPTUnallocated" -}}<span title="Unallocated balance, owned by asset"> ⚠️</span>{{- end -}}</td>
|
||||
<td class="data ellipsis">{{formatAmountWithDecimals $tokenTransfer.Value $tokenTransfer.Decimals}} {{$tokenTransfer.Symbol}}</td>
|
||||
<td class="data ellipsis">{{formatAmountWithDecimals $tokenTransfer.ValueOut $tokenTransfer.Decimals}} {{$tokenTransfer.Symbol}}</td>
|
||||
</tr>
|
||||
{{- end -}}{{- end -}}
|
||||
</tbody>
|
||||
|
|
Loading…
Reference in New Issue