Repository: trustwallet/blockatlas
Pull request #1381 (2021-01-23 06:34:45)

Implement basic block parsing metrics

codecov[bot]: # [Codecov](https://codecov.io/gh/trustwallet/blockatlas/pull/1381?src=pr&el=h1) Report
> Merging [#1381](https://codecov.io/gh/trustwallet/blockatlas/pull/1381?src=pr&el=desc) (978c9b1) into [master](https://codecov.io/gh/trustwallet/blockatlas/commit/97d9869e21aa5f0c6ed2ca36a72ac321f4f4ef15?el=desc) (97d9869) will **not change** coverage.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/trustwallet/blockatlas/pull/1381/graphs/tree.svg?width=650&height=150&src=pr&token=jnrjoEQAqv)](https://codecov.io/gh/trustwallet/blockatlas/pull/1381?src=pr&el=tree)

```diff
@@          Coverage Diff           @@
##           master   #1381   +/-   ##
======================================
  Coverage      44%     44%           
======================================
  Files         145     145           
  Lines        4159    4159           
======================================
  Hits         1868    1868           
  Misses       2123    2123           
  Partials      168     168           
```



------

[Continue to review full report at Codecov](https://codecov.io/gh/trustwallet/blockatlas/pull/1381?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/trustwallet/blockatlas/pull/1381?src=pr&el=footer). Last update [97d9869...978c9b1](https://codecov.io/gh/trustwallet/blockatlas/pull/1381?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/api/api.go b/api/api.go
index 2e9c950..978d51f 100644
--- a/api/api.go
+++ b/api/api.go
@@ -2,8 +2,10 @@ package api
 
 import (
 	"github.com/gin-gonic/gin"
+	"github.com/prometheus/client_golang/prometheus/promhttp"
 	ginSwagger "github.com/swaggo/gin-swagger"
 	"github.com/swaggo/gin-swagger/swaggerFiles"
+	"github.com/trustwallet/blockatlas/config"
 	_ "github.com/trustwallet/blockatlas/docs"
 	"github.com/trustwallet/blockatlas/platform"
 	"github.com/trustwallet/blockatlas/services/tokenindexer"
@@ -31,3 +33,7 @@ func SetupTokensIndexAPI(router gin.IRouter, instance tokenindexer.Instance) {
 func SetupSwaggerAPI(router gin.IRouter) {
 	router.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
 }
+
+func SetupMetrics(router gin.IRouter) {
+	router.GET(config.Default.Metrics.Path, gin.WrapH(promhttp.Handler()))
+}
diff --git a/api/endpoint/collection.go b/api/endpoint/collection.go
index cebf4af..a57313f 100644
--- a/api/endpoint/collection.go
+++ b/api/endpoint/collection.go
@@ -6,6 +6,7 @@ import (
 
 	"github.com/gin-gonic/gin"
 	"github.com/trustwallet/blockatlas/pkg/blockatlas"
+	"github.com/trustwallet/golibs/coin"
 	"github.com/trustwallet/golibs/types"
 )
 
@@ -46,16 +47,30 @@ func GetCollectionCategoriesFromList(c *gin.Context, apis blockatlas.Collections
 		return
 	}
 
-	batch := make(types.CollectionPage, 0)
-	for key, addresses := range reqs {
-		coinId, err := strconv.Atoi(key)
+	reqIds := []int{}
+	coinIds := []int{}
+	for k := range reqs {
+		coinId, err := strconv.Atoi(k)
 		if err != nil {
 			continue
 		}
+		reqIds = append(reqIds, coinId)
+	}
+
+	// old iOS client requests all accounts
+	if len(reqIds) > 2 {
+		coinIds = append(coinIds, coin.ETHEREUM)
+	} else {
+		coinIds = reqIds
+	}
+
+	batch := make(types.CollectionPage, 0)
+	for _, coinId := range coinIds {
 		p, ok := apis[uint(coinId)]
 		if !ok {
 			continue
 		}
+		addresses := reqs[strconv.Itoa(coinId)]
 		for _, address := range addresses {
 			collections, err := p.GetCollections(address)
 			if err != nil {
diff --git a/cmd/api/main.go b/cmd/api/main.go
index 98a1664..303bd3d 100644
--- a/cmd/api/main.go
+++ b/cmd/api/main.go
@@ -3,6 +3,8 @@ package main
 import (
 	"context"
 
+	"github.com/trustwallet/blockatlas/internal/metrics"
+
 	golibsGin "github.com/trustwallet/golibs/network/gin"
 
 	"github.com/trustwallet/golibs/network/middleware"
@@ -51,6 +53,8 @@ func init() {
 		log.Fatal(err)
 	}
 
+	metrics.Setup(database)
+
 	tokenIndexer = tokenindexer.Init(database)
 }
 
@@ -58,6 +62,7 @@ func main() {
 	api.SetupTokensIndexAPI(engine, tokenIndexer)
 	api.SetupSwaggerAPI(engine)
 	api.SetupPlatformAPI(engine)
+	api.SetupMetrics(engine)
 
 	golibsGin.SetupGracefulShutdown(ctx, port, engine)
 	cancel()
diff --git a/config.yml b/config.yml
index 11e71f6..f06968e 100644
--- a/config.yml
+++ b/config.yml
@@ -59,7 +59,6 @@ ethereum:
   api: https://localhost:4567 #(Trust-Ray API)
   collections_api: https://api.opensea.io
   #  collections_api_key: [opensea_api_key]
-  rpc: https://main-rpc.linkpool.io
 
 # [ETC] Ethereum Classic: https://ethereumclassic.org (Trust-Ray API)
 classic:
@@ -216,10 +215,12 @@ filecoin:
   api: https://api.filscan.io:8700/rpc/v1
   explorer: https://filfox.info
 
-# smartchain:
-#   api: <blockbook api>
-#   rpc: https://bsc-dataseed.nariox.org
-#   collections_api: https://nftview.bounce.finance
+smartchain:
+  api: <blockbook api>
+  collections_api: https://nftview.bounce.finance
 
 sentry:
   dsn: ""
+
+metrics:
+  path: metrics
diff --git a/config/configuration.go b/config/configuration.go
index 0f149f5..80a0bed 100755
--- a/config/configuration.go
+++ b/config/configuration.go
@@ -35,7 +35,6 @@ type Configuration struct {
 		BlockbookAPI   string `mapstructure:"blockbook_api"`
 		CollectionsAPI string `mapstructure:"collections_api"`
 		CollectionsKey string `mapstructure:"collections_api_key"`
-		RPC            string `mapstructure:"rpc"`
 	} `mapstructure:"ethereum"`
 	Binance struct {
 		API string `mapstructure:"api"`
@@ -69,14 +68,8 @@ type Configuration struct {
 	} `mapstructure:"classic"`
 	Smartchain struct {
 		API            string `mapstructure:"api"`
-		RPC            string `mapstructure:"rpc"`
 		CollectionsAPI string `mapstructure:"collections_api"`
 	} `mapstructure:"smartchain"`
-	BSC struct {
-		API            string `mapstructure:"api"`
-		RPC            string `mapstructure:"rpc"`
-		CollectionsAPI string `mapstructure:"collections_api"`
-	} `mapstructure:"bsc"`
 	Poa struct {
 		API string `mapstructure:"api"`
 		RPC string `mapstructure:"rpc"`
@@ -213,6 +206,9 @@ type Configuration struct {
 	Sentry struct {
 		DSN string `mapstructure:"dsn"`
 	} `mapstructure:"sentry"`
+	Metrics struct {
+		Path string `mapstructure:"path"`
+	} `mapstructure:"metrics"`
 	Consumer struct {
 		Service  string `mapstructure:"service"`
 		Prefetch int    `mapstructure:"prefetch"`
diff --git a/db/models/tracker.go b/db/models/tracker.go
index fdead1c..87b471f 100644
--- a/db/models/tracker.go
+++ b/db/models/tracker.go
@@ -5,6 +5,7 @@ import "time"
 type Tracker struct {
 	UpdatedAt time.Time
 	Coin      string `gorm:"primary_key:true; type:varchar(64)"`
+	Priority  string `gorm:"default:normal"`
 	Height    int64
 	Enabled   bool `gorm:"default:true" sql:"index"`
 }
diff --git a/db/tracker.go b/db/tracker.go
index 08e61e0..0cf6dbc 100644
--- a/db/tracker.go
+++ b/db/tracker.go
@@ -5,6 +5,15 @@ import (
 	"gorm.io/gorm/clause"
 )
 
+func (i *Instance) GetLastParsedBlockNumbers() ([]models.Tracker, error) {
+	var trackers []models.Tracker
+	if err := i.Gorm.
+		Find(&trackers).Error; err != nil {
+		return trackers, nil
+	}
+	return trackers, nil
+}
+
 func (i *Instance) GetLastParsedBlockNumber(coin string) (models.Tracker, error) {
 	var tracker models.Tracker
 	if err := i.Gorm.
diff --git a/go.mod b/go.mod
index c045efa..6b0af5c 100644
--- a/go.mod
+++ b/go.mod
@@ -18,18 +18,19 @@ require (
 	github.com/opencontainers/runc v1.0.0-rc9 // indirect
 	github.com/ory/dockertest v3.3.5+incompatible
 	github.com/patrickmn/go-cache v2.1.0+incompatible
+	github.com/prometheus/client_golang v0.9.3
 	github.com/sirupsen/logrus v1.7.0
 	github.com/spf13/viper v1.7.1
 	github.com/streadway/amqp v1.0.0
 	github.com/stretchr/testify v1.7.0
 	github.com/swaggo/gin-swagger v1.3.0
 	github.com/swaggo/swag v1.7.0
-	github.com/trustwallet/golibs v0.0.41
-	github.com/trustwallet/golibs/network v0.0.0-20210122201441-617190ec568d
+	github.com/trustwallet/golibs v0.1.0
+	github.com/trustwallet/golibs/network v0.0.0-20210124080535-8638b407c4ab
 	golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392
 	golang.org/x/net v0.0.0-20210119194325-5f4716e94777 // indirect
 	golang.org/x/sys v0.0.0-20210123231150-1d476976d117 // indirect
 	gopkg.in/yaml.v2 v2.4.0
-	gorm.io/driver/postgres v1.0.6
-	gorm.io/gorm v1.20.11
+	gorm.io/driver/postgres v1.0.7
+	gorm.io/gorm v1.20.12
 )
diff --git a/go.sum b/go.sum
index b67c7a2..3727e13 100644
--- a/go.sum
+++ b/go.sum
@@ -38,6 +38,7 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
 github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
@@ -302,6 +303,7 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
 github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
 github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
 github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
@@ -349,12 +351,16 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=
 github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
 github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY=
 github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
@@ -420,10 +426,10 @@ github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6A
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/trustwallet/golibs v0.0.35 h1:VqWInO5s4Zg6XyCmqro8/xrEViOedZ3oYtBq/kn4fBg=
 github.com/trustwallet/golibs v0.0.35/go.mod h1:VI0APImKAYxvJ8MnMD6aHSKvnArXUd3NgNEghX5P+K8=
-github.com/trustwallet/golibs v0.0.41 h1:6BIPoZVWXZqgq/9pFiPyLvooeyide9EAiPu8ig7DMnA=
-github.com/trustwallet/golibs v0.0.41/go.mod h1:SQ3mijAuOTX9GRyaqph3NY2ox04JD5WQ6PkWqX2NB8w=
-github.com/trustwallet/golibs/network v0.0.0-20210122201441-617190ec568d h1:18DDeaIYbff7K2bS4PB6PYgROEtGUBsU8F9KeqTnuXg=
-github.com/trustwallet/golibs/network v0.0.0-20210122201441-617190ec568d/go.mod h1:LDMLFnOnwmC30WuCCIJ56TWeXxwCVcrMFJYeC6GEnxY=
+github.com/trustwallet/golibs v0.1.0 h1:uo52Hy3WTfGkkd1Y7ti5Hl6BPhvudXG5BlmhBtgtQ6Y=
+github.com/trustwallet/golibs v0.1.0/go.mod h1:SQ3mijAuOTX9GRyaqph3NY2ox04JD5WQ6PkWqX2NB8w=
+github.com/trustwallet/golibs/network v0.0.0-20210124080535-8638b407c4ab h1:djqS58OXHs6tkRoCyuPnMu5q5woQj/1bxUFnSN0Xlew=
+github.com/trustwallet/golibs/network v0.0.0-20210124080535-8638b407c4ab/go.mod h1:LDMLFnOnwmC30WuCCIJ56TWeXxwCVcrMFJYeC6GEnxY=
 github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
 github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
 github.com/ugorji/go v1.1.13 h1:nB3O5kBSQGjEQAcfe1aLUYuxmXdFKmYgBZhY32rQb6Q=
@@ -642,12 +648,10 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gorm.io/driver/postgres v1.0.6 h1:9sqNcNC9PCkZ6tMzWF1cEE2PARlCONgSqRobszSTffw=
-gorm.io/driver/postgres v1.0.6/go.mod h1:r0nvX27yHDNbVeXMM9Y+9i5xSePcT18RfH8clP6wpwI=
-gorm.io/gorm v1.20.8 h1:iToaOdZgjNvlc44NFkxfLa3U9q63qwaxt0FdNCiwOMs=
-gorm.io/gorm v1.20.8/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
-gorm.io/gorm v1.20.11 h1:jYHQ0LLUViV85V8dM1TP9VBBkfzKTnuTXDjYObkI6yc=
-gorm.io/gorm v1.20.11/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
+gorm.io/driver/postgres v1.0.7 h1:uCVjh1w7DSZ20Duo10JadA+1a0OZpgJk/o/z8pFpNQs=
+gorm.io/driver/postgres v1.0.7/go.mod h1:4eOzrI1MUfm6ObJU/UcmbXyiHSs8jSwH95G5P5dxcAg=
+gorm.io/gorm v1.20.12 h1:ebZ5KrSHzet+sqOCVdH9mTjW91L298nX3v5lVxAzSUY=
+gorm.io/gorm v1.20.12/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
 gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
 gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go
new file mode 100644
index 0000000..23b6008
--- /dev/null
+++ b/internal/metrics/metrics.go
@@ -0,0 +1,51 @@
+package metrics
+
+import (
+	"time"
+
+	"github.com/trustwallet/blockatlas/db"
+
+	"github.com/prometheus/client_golang/prometheus"
+)
+
+var (
+	namespace = "blockatlas"
+
+	workerBlockParsing = prometheus.NewGaugeVec(
+		prometheus.GaugeOpts{
+			Namespace: namespace,
+			Subsystem: "worker",
+			Name:      "block_parsing",
+			Help:      "Last parsed block",
+		},
+		[]string{
+			"coin",
+			"priority",
+		},
+	)
+)
+
+func setupUpdateTrackerMetrics(db *db.Instance) {
+	go func() {
+		for {
+			trackers, err := db.GetLastParsedBlockNumbers()
+			if err != nil {
+				continue
+			}
+			for _, tracker := range trackers {
+				labels := prometheus.Labels{"coin": tracker.Coin, "priority": tracker.Priority}
+				workerBlockParsing.With(labels).Set(float64(tracker.Height))
+			}
+			time.Sleep(1 * time.Second)
+		}
+	}()
+}
+
+func Setup(db *db.Instance) {
+	prometheus.DefaultRegisterer.Unregister(prometheus.NewGoCollector())
+	prometheus.DefaultRegisterer.Unregister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}))
+
+	prometheus.MustRegister(workerBlockParsing)
+
+	setupUpdateTrackerMetrics(db)
+}
diff --git a/platform/aeternity/base.go b/platform/aeternity/base.go
index 3ce61c2..9b17b61 100644
--- a/platform/aeternity/base.go
+++ b/platform/aeternity/base.go
@@ -17,5 +17,5 @@ func Init(api string) *Platform {
 }
 
 func (p *Platform) Coin() coin.Coin {
-	return coin.Coins[coin.AE]
+	return coin.Aeternity()
 }
diff --git a/platform/aeternity/transaction.go b/platform/aeternity/transaction.go
index 5544e94..9038fa7 100644
--- a/platform/aeternity/transaction.go
+++ b/platform/aeternity/transaction.go
@@ -28,7 +28,7 @@ func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) {
 
 func NormalizeTx(srcTx *Transaction) (types.Tx, error) {
 	txValue := srcTx.TxValue
-	decimals := coin.Coins[coin.AE].Decimals
+	decimals := coin.Aeternity().Decimals
 	amountFloat, err := txValue.Amount.Float64()
 	if err != nil {
 		return types.Tx{}, err
@@ -36,7 +36,7 @@ func NormalizeTx(srcTx *Transaction) (types.Tx, error) {
 	amount := numbers.Float64toString(amountFloat)
 	return types.Tx{
 		ID:       srcTx.Hash,
-		Coin:     coin.AE,
+		Coin:     coin.AETERNITY,
 		From:     txValue.Sender,
 		To:       txValue.Recipient,
 		Fee:      types.Amount(txValue.Fee),
@@ -47,7 +47,7 @@ func NormalizeTx(srcTx *Transaction) (types.Tx, error) {
 		Sequence: txValue.Nonce,
 		Meta: types.Transfer{
 			Value:    types.Amount(amount),
-			Symbol:   coin.Coins[coin.AE].Symbol,
+			Symbol:   coin.Aeternity().Symbol,
 			Decimals: decimals,
 		},
 	}, nil
diff --git a/platform/algorand/base.go b/platform/algorand/base.go
index c479464..24bb608 100644
--- a/platform/algorand/base.go
+++ b/platform/algorand/base.go
@@ -15,5 +15,5 @@ func Init(api, apiKey string) *Platform {
 }
 
 func (p *Platform) Coin() coin.Coin {
-	return coin.Coins[coin.ALGO]
+	return coin.Algorand()
 }
diff --git a/platform/algorand/transaction.go b/platform/algorand/transaction.go
index 80be3a3..89db41a 100644
--- a/platform/algorand/transaction.go
+++ b/platform/algorand/transaction.go
@@ -35,7 +35,7 @@ func Normalize(tx Transaction) (result types.Tx, ok bool) {
 
 	return types.Tx{
 		ID:     tx.Hash,
-		Coin:   coin.ALGO,
+		Coin:   coin.ALGORAND,
 		From:   tx.From,
 		To:     tx.Payment.Receiver,
 		Fee:    types.Amount(strconv.Itoa(int(tx.Fee))),
@@ -45,8 +45,8 @@ func Normalize(tx Transaction) (result types.Tx, ok bool) {
 		Type:   types.TxTransfer,
 		Meta: types.Transfer{
 			Value:    types.Amount(strconv.Itoa(int(tx.Payment.Amount))),
-			Symbol:   coin.Coins[coin.ALGO].Symbol,
-			Decimals: coin.Coins[coin.ALGO].Decimals,
+			Symbol:   coin.Algorand().Symbol,
+			Decimals: coin.Algorand().Decimals,
 		},
 	}, true
 }
diff --git a/platform/ethereum/base.go b/platform/ethereum/base.go
index 3cf04c2..3f2446f 100644
--- a/platform/ethereum/base.go
+++ b/platform/ethereum/base.go
@@ -12,35 +12,32 @@ import (
 
 type Platform struct {
 	CoinIndex   uint
-	RpcURL      string
 	client      EthereumClient
 	collectible CollectibleClient
 }
 
-func Init(coinType uint, api, rpc string) *Platform {
+func InitTrustRay(coinType uint, api string) *Platform {
 	return &Platform{
 		CoinIndex: coinType,
-		RpcURL:    rpc,
 		client:    &trustray.Client{Request: client.InitClient(api, middleware.SentryErrorHandler)},
 	}
 }
 
-func InitWithBlockbook(coinType uint, blockbookApi, rpc string) *Platform {
+func InitWithBlockbook(coinType uint, blockbookApi string) *Platform {
 	return &Platform{
 		CoinIndex: coinType,
-		RpcURL:    rpc,
 		client:    &blockbook.Client{Request: client.InitClient(blockbookApi, middleware.SentryErrorHandler)},
 	}
 }
 
-func InitWithOpenSea(coinType uint, rpc, blockbookApi, collectionApi, collectionKey string) *Platform {
-	platform := InitWithBlockbook(coinType, blockbookApi, rpc)
+func InitWithOpenSea(coinType uint, blockbookApi, collectionApi, collectionKey string) *Platform {
+	platform := InitWithBlockbook(coinType, blockbookApi)
 	platform.collectible = opensea.InitClient(collectionApi, collectionKey)
 	return platform
 }
 
-func InitWithBounce(coinType uint, rpc, blockbookApi, collectionApi string) *Platform {
-	platform := InitWithBlockbook(coinType, blockbookApi, rpc)
+func InitWithBounce(coinType uint, blockbookApi, collectionApi string) *Platform {
+	platform := InitWithBlockbook(coinType, blockbookApi)
 	platform.collectible = bounce.InitClient(collectionApi)
 	return platform
 }
diff --git a/platform/ethereum/bounce/client.go b/platform/ethereum/bounce/client.go
index 04fb8cd..465cf79 100644
--- a/platform/ethereum/bounce/client.go
+++ b/platform/ethereum/bounce/client.go
@@ -4,7 +4,6 @@ import (
 	"errors"
 	"fmt"
 	"net/url"
-	"strconv"
 	"strings"
 
 	"github.com/trustwallet/golibs/client"
@@ -25,28 +24,26 @@ func InitClient(url string) *Client {
 	return &c
 }
 
-func (c Client) getCollections(owner string, chainId int) ([]Collection, error) {
+func (c Client) getCollections(owner string) ([]Collection, error) {
 	query := url.Values{
-		"address":  {owner},
-		"chain_id": {strconv.Itoa(chainId)},
+		"user_address": {owner},
 	}
 	var resp CollectionResponse
-	err := c.Get(&resp, "nft", query)
+	err := c.Get(&resp, "/v2/bsc/nft", query)
 	if err != nil {
 		return nil, err
 	}
 	return resp.Data.Collections, nil
 }
 
-func (c Client) getCollectibles(owner string, collectionID string, chainId int) ([]Collectible, error) {
+func (c Client) getCollectibles(owner string, collectionID string) ([]Collectible, error) {
 	query := url.Values{
-		"user_addr":     {owner},
-		"contract_addr": {collectionID},
-		"chain_id":      {strconv.Itoa(chainId)},
+		"user_address":     {owner},
+		"contract_address": {collectionID},
 	}
 
 	var resp CollectibleResponse
-	err := c.Get(&resp, "erc721", query)
+	err := c.Get(&resp, "/v2/bsc/erc721", query)
 	if err != nil {
 		return nil, err
 	}
@@ -72,7 +69,7 @@ func fetchTokenURI(uri string) (info CollectionInfo, err error) {
 	return
 }
 
-func normalizeImageUrl(uri string) string {
+func normalizeUrl(uri string) string {
 	url, err := url.Parse(uri)
 	if err != nil {
 		return uri
@@ -84,5 +81,8 @@ func normalizeImageUrl(uri string) string {
 }
 
 func ipfsGatewayUrl(url *url.URL) string {
-	return fmt.Sprintf("https://ipfs.io/ipfs/%s%s", url.Host, url.Path)
+	components := strings.TrimPrefix(url.String(), ipfsScheme+"://")
+	components = strings.TrimPrefix(components, "/")
+	components = strings.TrimPrefix(components, "ipfs/")
+	return fmt.Sprintf("https://ipfs.io/ipfs/%s", components)
 }
diff --git a/platform/ethereum/bounce/collection.go b/platform/ethereum/bounce/collection.go
index 0058cf6..1fd17a6 100644
--- a/platform/ethereum/bounce/collection.go
+++ b/platform/ethereum/bounce/collection.go
@@ -8,28 +8,27 @@ import (
 )
 
 var (
-	bscChainId = 56
 	nftVersion = "3.0" // opensea nft_version compatible
 )
 
 func (c *Client) GetCollections(owner string, coinIndex uint) (types.CollectionPage, error) {
-	collections, err := c.getCollections(owner, bscChainId)
+	collections, err := c.getCollections(owner)
 	if err != nil {
 		return nil, err
 	}
-	return c.NormalizeCollections(collections, coinIndex, owner)
+	return c.processCollections(collections, coinIndex, owner)
 
 }
 
 func (c *Client) GetCollectibles(owner, collectionID string, coinIndex uint) (types.CollectiblePage, error) {
-	collectibles, err := c.getCollectibles(owner, collectionID, bscChainId)
+	collectibles, err := c.getCollectibles(owner, collectionID)
 	if err != nil {
 		return nil, err
 	}
-	return c.NormalizeCollectibles(collectibles, coinIndex)
+	return c.processCollectibles(collectibles, coinIndex)
 }
 
-func (c *Client) NormalizeCollections(collections []Collection, coinIndex uint, owner string) (types.CollectionPage, error) {
+func (c *Client) processCollections(collections []Collection, coinIndex uint, owner string) (types.CollectionPage, error) {
 	page := make(types.CollectionPage, 0)
 	category := map[string]bool{}
 	for _, cl := range collections {
@@ -61,9 +60,9 @@ func (c *Client) NormalizeCollections(collections []Collection, coinIndex uint,
 		page = append(page, types.Collection{
 			Id:           cl.ContractAddr,
 			Name:         info.Name,
-			ImageUrl:     normalizeImageUrl(info.Image),
+			ImageUrl:     normalizeUrl(info.Image),
 			Description:  info.Description,
-			ExternalLink: cl.TokenURI,
+			ExternalLink: normalizeUrl(cl.TokenURI),
 			Total:        total,
 			Address:      owner,
 			Coin:         coinIndex,
@@ -74,7 +73,7 @@ func (c *Client) NormalizeCollections(collections []Collection, coinIndex uint,
 	return page, nil
 }
 
-func (c *Client) NormalizeCollectibles(collectibles []Collectible, coinIndex uint) (types.CollectiblePage, error) {
+func (c *Client) processCollectibles(collectibles []Collectible, coinIndex uint) (types.CollectiblePage, error) {
 	if len(collectibles) == 0 {
 		return types.CollectiblePage{}, nil
 	}
@@ -84,20 +83,29 @@ func (c *Client) NormalizeCollectibles(collectibles []Collectible, coinIndex uin
 		return nil, err
 	}
 	for _, c := range collectibles {
-		tokenId := strconv.Itoa(c.TokenID)
-		page = append(page, types.Collectible{
-			ID:              blockatlas.GenCollectibleId(c.ContractAddr, tokenId),
-			CollectionID:    c.ContractAddr,
-			TokenID:         tokenId,
-			ContractAddress: c.ContractAddr,
-			ImageUrl:        normalizeImageUrl(info.Image),
-			ExternalLink:    c.TokenURI,
-			Type:            string(types.ERC721),
-			Description:     info.Description,
-			Coin:            coinIndex,
-			Name:            info.Name,
-			Version:         nftVersion,
-		})
+		normalized := normalizeCollectible(c, coinIndex, info)
+		page = append(page, normalized)
 	}
 	return page, nil
 }
+
+func normalizeCollectible(c Collectible, coinIndex uint, info CollectionInfo) types.Collectible {
+	category := c.ContractName
+	if len(category) == 0 {
+		category = info.Name
+	}
+	return types.Collectible{
+		ID:              blockatlas.GenCollectibleId(c.ContractAddr, c.TokenID),
+		CollectionID:    c.ContractAddr,
+		TokenID:         c.TokenID,
+		ContractAddress: c.ContractAddr,
+		Category:        category,
+		ImageUrl:        normalizeUrl(info.Image),
+		ExternalLink:    normalizeUrl(c.TokenURI),
+		Type:            string(types.ERC721),
+		Description:     info.Description,
+		Coin:            coinIndex,
+		Name:            info.Name,
+		Version:         nftVersion,
+	}
+}
diff --git a/platform/ethereum/bounce/mocks/artwork_nft.json b/platform/ethereum/bounce/mocks/artwork_nft.json
new file mode 100644
index 0000000..1cc7521
--- /dev/null
+++ b/platform/ethereum/bounce/mocks/artwork_nft.json
@@ -0,0 +1,22 @@
+{
+  "id": 63039,
+  "contract_addr": "0x5Bc94e9347F3b9Be8415bDfd24af16666704E44f",
+  "contract_name": "",
+  "token_type": "721",
+  "token_id": "450",
+  "owner_addr": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1",
+  "balance": "1",
+  "token_uri": "https://www.bakeryswap.org/api/v1/artworks/fb4576253e3d45cebf0ac4c8df8f1743",
+  "name": null,
+  "description": null,
+  "image": null,
+  "metadata": {
+    "description": "Animal Series",
+    "image": "https://d3ggs2vjn5heyw.cloudfront.net/static/nfts/artworks/d9dc679ec0614eb78b479aed21694305.jpg",
+    "name": "Hungry",
+    "properties": {
+      "artist": "srnArt",
+      "public_profile_link": "https://twitter.com/srn_art?s=09"
+    }
+  }
+}
diff --git a/platform/ethereum/bounce/mocks/pancake_bunny.json b/platform/ethereum/bounce/mocks/pancake_bunny.json
new file mode 100644
index 0000000..decb0f8
--- /dev/null
+++ b/platform/ethereum/bounce/mocks/pancake_bunny.json
@@ -0,0 +1,21 @@
+{
+  "id": 48963,
+  "contract_addr": "0xDf7952B35f24aCF7fC0487D01c8d5690a60DBa07",
+  "contract_name": "Pancake Bunnies",
+  "token_type": "721",
+  "token_id": "409",
+  "owner_addr": "0x7d8bf18c7ce84b3e175b339c4ca93aed1dd166f1",
+  "balance": "1",
+  "token_uri": "ipfs://QmYu9WwPNKNSZQiTCDfRk7aCR472GURavR9M1qosDmqpev/swapsies.json",
+  "name": null,
+  "description": null,
+  "image": null,
+  "metadata": {
+    "attributes": {
+      "bunnyId": "0"
+    },
+    "description": "These bunnies love nothing more than swapping pancakes. Especially on BSC.",
+    "image": "ipfs://QmXdHqg3nywpNJWDevJQPtkz93vpfoHcZWQovFz2nmtPf5/swapsies.png",
+    "name": "Swapsies"
+  }
+}
diff --git a/platform/ethereum/bounce/model.go b/platform/ethereum/bounce/model.go
index 8e1d54c..cbec7cc 100644
--- a/platform/ethereum/bounce/model.go
+++ b/platform/ethereum/bounce/model.go
@@ -1,15 +1,15 @@
 package bounce
 
 type Response struct {
-	CodeStatus int    `json:"codeStatus"`
-	Msg        string `json:"msg"`
+	Code int    `json:"code"`
+	Msg  string `json:"msg"`
 }
 
 type Collectible struct {
 	ContractAddr string `json:"contract_addr"`
-	TokenID      int    `json:"token_id"`
+	ContractName string `json:"contract_name,omitempty"`
+	TokenID      string `json:"token_id"`
 	OwnerAddr    string `json:"owner_addr"`
-	ChainID      int    `json:"chain_id"`
 	TokenURI     string `json:"token_uri"`
 }
 
@@ -25,15 +25,14 @@ type CollectibleResponse struct {
 type Collection struct {
 	ContractAddr string `json:"contract_addr"`
 	TokenType    string `json:"token_type"`
-	TokenID      int    `json:"token_id"`
+	TokenID      string `json:"token_id"`
 	OwnerAddr    string `json:"owner_addr"`
-	ChainID      int    `json:"chain_id"`
 	Balance      string `json:"balance"`
 	TokenURI     string `json:"token_uri"`
 }
 
 type CollectionList struct {
-	Collections []Collection `json:"nfts"`
+	Collections []Collection `json:"nfts721"`
 }
 
 type CollectionResponse struct {
diff --git a/platform/filecoin/base.go b/platform/filecoin/base.go
index 97016a4..ce454d3 100644
--- a/platform/filecoin/base.go
+++ b/platform/filecoin/base.go
@@ -22,5 +22,5 @@ func Init(api, explorerApi string) *Platform {
 }
 
 func (p *Platform) Coin() coin.Coin {
-	return coin.Coins[coin.FIL]
+	return coin.Filecoin()
 }
diff --git a/platform/harmony/base.go b/platform/harmony/base.go
index 1d4d766..18b2b98 100644
--- a/platform/harmony/base.go
+++ b/platform/harmony/base.go
@@ -18,5 +18,5 @@ func Init(api string) *Platform {
 }
 
 func (p *Platform) Coin() coin.Coin {
-	return coin.Coins[coin.ONE]
+	return coin.Harmony()
 }
diff --git a/platform/harmony/transaction.go b/platform/harmony/transaction.go
index ab8af95..144e116 100644
--- a/platform/harmony/transaction.go
+++ b/platform/harmony/transaction.go
@@ -64,7 +64,7 @@ func NormalizeTx(trx *Transaction) (tx types.Tx, b bool, err error) {
 
 	return types.Tx{
 		ID:       trx.Hash,
-		Coin:     coin.ONE,
+		Coin:     coin.HARMONY,
 		From:     trx.From,
 		To:       trx.To,
 		Fee:      types.Amount(literalFee),
@@ -75,8 +75,8 @@ func NormalizeTx(trx *Transaction) (tx types.Tx, b bool, err error) {
 		Block:    block,
 		Meta: types.Transfer{
 			Value:    types.Amount(literalValue),
-			Symbol:   coin.Coins[coin.ONE].Symbol,
-			Decimals: coin.Coins[coin.ONE].Decimals,
+			Symbol:   coin.Harmony().Symbol,
+			Decimals: coin.Harmony().Decimals,
 		},
 	}, true, nil
 }
diff --git a/platform/icon/base.go b/platform/icon/base.go
index 8d15629..8950fbd 100644
--- a/platform/icon/base.go
+++ b/platform/icon/base.go
@@ -17,5 +17,5 @@ func Init(api string) *Platform {
 }
 
 func (p *Platform) Coin() coin.Coin {
-	return coin.Coins[coin.ICX]
+	return coin.Icon()
 }
diff --git a/platform/icon/transaction.go b/platform/icon/transaction.go
index 6fed6e1..ffd795b 100644
--- a/platform/icon/transaction.go
+++ b/platform/icon/transaction.go
@@ -39,7 +39,7 @@ func Normalize(trx *Tx) (tx types.Tx, b bool) {
 
 	return types.Tx{
 		ID:     trx.TxHash,
-		Coin:   coin.ICX,
+		Coin:   coin.ICON,
 		From:   trx.FromAddr,
 		To:     trx.ToAddr,
 		Fee:    types.Amount(fee),
@@ -49,8 +49,8 @@ func Normalize(trx *Tx) (tx types.Tx, b bool) {
 		Block:  trx.Height,
 		Meta: types.Transfer{
 			Value:    types.Amount(value),
-			Symbol:   coin.Coins[coin.ICX].Symbol,
-			Decimals: coin.Coins[coin.ICX].Decimals,
+			Symbol:   coin.Icon().Symbol,
+			Decimals: coin.Icon().Decimals,
 		},
 	}, true
 }
diff --git a/platform/iotex/base.go b/platform/iotex/base.go
index bed4435..e053e37 100644
--- a/platform/iotex/base.go
+++ b/platform/iotex/base.go
@@ -17,5 +17,5 @@ func Init(api string) *Platform {
 }
 
 func (p *Platform) Coin() coin.Coin {
-	return coin.Coins[coin.IOTX]
+	return coin.Iotex()
 }
diff --git a/platform/iotex/transaction.go b/platform/iotex/transaction.go
index 4da1c7c..2cbe0af 100644
--- a/platform/iotex/transaction.go
+++ b/platform/iotex/transaction.go
@@ -68,7 +68,7 @@ func Normalize(trx *ActionInfo) *types.Tx {
 	}
 	return &types.Tx{
 		ID:       trx.ActHash,
-		Coin:     coin.IOTX,
+		Coin:     coin.IOTEX,
 		From:     trx.Sender,
 		To:       trx.Action.Core.Transfer.Recipient,
 		Fee:      types.Amount(trx.GasFee),
@@ -79,8 +79,8 @@ func Normalize(trx *ActionInfo) *types.Tx {
 		Type:     types.TxTransfer,
 		Meta: types.Transfer{
 			Value:    trx.Action.Core.Transfer.Amount,
-			Symbol:   coin.Coins[coin.IOTX].Symbol,
-			Decimals: coin.Coins[coin.IOTX].Decimals,
+			Symbol:   coin.Iotex().Symbol,
+			Decimals: coin.Iotex().Decimals,
 		},
 	}
 }
diff --git a/platform/nebulas/base.go b/platform/nebulas/base.go
index 99dfedf..3418994 100644
--- a/platform/nebulas/base.go
+++ b/platform/nebulas/base.go
@@ -17,5 +17,5 @@ func Init(api string) *Platform {
 }
 
 func (p *Platform) Coin() coin.Coin {
-	return coin.Coins[coin.NAS]
+	return coin.Nebulas()
 }
diff --git a/platform/nebulas/transaction.go b/platform/nebulas/transaction.go
index 0f0d789..b51d496 100644
--- a/platform/nebulas/transaction.go
+++ b/platform/nebulas/transaction.go
@@ -45,7 +45,7 @@ func NormalizeTx(srcTx Transaction) types.Tx {
 	}
 	return types.Tx{
 		ID:       srcTx.Hash,
-		Coin:     coin.NAS,
+		Coin:     coin.NEBULAS,
 		From:     srcTx.From.Hash,
 		To:       srcTx.To.Hash,
 		Fee:      types.Amount(srcTx.TxFee),
@@ -55,8 +55,8 @@ func NormalizeTx(srcTx Transaction) types.Tx {
 		Sequence: srcTx.Nonce,
 		Meta: types.Transfer{
 			Value:    types.Amount(srcTx.Value),
-			Symbol:   coin.Coins[coin.NAS].Symbol,
-			Decimals: coin.Coins[coin.NAS].Decimals,
+			Symbol:   coin.Nebulas().Symbol,
+			Decimals: coin.Nebulas().Decimals,
 		},
 	}
 }
diff --git a/platform/nimiq/base.go b/platform/nimiq/base.go
index 7a65ee9..690992c 100644
--- a/platform/nimiq/base.go
+++ b/platform/nimiq/base.go
@@ -17,5 +17,5 @@ func Init(api string) *Platform {
 }
 
 func (p *Platform) Coin() coin.Coin {
-	return coin.Coins[coin.NIM]
+	return coin.Nimiq()
 }
diff --git a/platform/nimiq/transaction.go b/platform/nimiq/transaction.go
index 2a0e143..5124a79 100644
--- a/platform/nimiq/transaction.go
+++ b/platform/nimiq/transaction.go
@@ -25,7 +25,7 @@ func NormalizeTx(srcTx *Tx) types.Tx {
 	}
 	return types.Tx{
 		ID:    srcTx.Hash,
-		Coin:  coin.NIM,
+		Coin:  coin.NIMIQ,
 		Date:  date,
 		From:  srcTx.FromAddress,
 		To:    srcTx.ToAddress,
@@ -33,8 +33,8 @@ func NormalizeTx(srcTx *Tx) types.Tx {
 		Block: srcTx.BlockNumber,
 		Meta: types.Transfer{
 			Value:    srcTx.Value,
-			Symbol:   coin.Coins[coin.NIM].Symbol,
-			Decimals: coin.Coins[coin.NIM].Decimals,
+			Symbol:   coin.Nimiq().Symbol,
+			Decimals: coin.Nimiq().Decimals,
 		},
 	}
 }
diff --git a/platform/ontology/base.go b/platform/ontology/base.go
index a469413..6047ac5 100644
--- a/platform/ontology/base.go
+++ b/platform/ontology/base.go
@@ -17,5 +17,5 @@ func Init(api string) *Platform {
 }
 
 func (p *Platform) Coin() coin.Coin {
-	return coin.Coins[coin.ONT]
+	return coin.Ontology()
 }
diff --git a/platform/ontology/transaction.go b/platform/ontology/transaction.go
index c8c9109..e98d6ea 100644
--- a/platform/ontology/transaction.go
+++ b/platform/ontology/transaction.go
@@ -33,7 +33,7 @@ func Normalize(srcTx *Tx, assetName AssetType) (tx types.Tx, ok bool) {
 	}
 	tx = types.Tx{
 		ID:     srcTx.Hash,
-		Coin:   coin.ONT,
+		Coin:   coin.ONTOLOGY,
 		Fee:    types.Amount(fee),
 		Date:   srcTx.Time,
 		Block:  srcTx.Height,
diff --git a/platform/platform.go b/platform/platform.go
index ce218ce..171c374 100644
--- a/platform/platform.go
+++ b/platform/platform.go
@@ -67,41 +67,42 @@ func getAllHandlers() blockatlas.Platforms {
 		coin.Tezos().Handle:        tezos.Init(config.Default.Tezos.API, config.Default.Tezos.RPC, config.Default.Tezos.Baker),
 		coin.Binance().Handle:      binance.Init(config.Default.Binance.API, config.Default.Binance.Key),
 		coin.Zilliqa().Handle:      zilliqa.Init(config.Default.Zilliqa.API, config.Default.Zilliqa.Key, config.Default.Zilliqa.RPC),
-		coin.Polkadot().Handle:     polkadot.Init(coin.DOT, config.Default.Polkadot.API),
-		coin.Stellar().Handle:      stellar.Init(coin.XLM, config.Default.Stellar.API),
-		coin.Cosmos().Handle:       cosmos.Init(coin.ATOM, config.Default.Cosmos.API),
+		coin.Polkadot().Handle:     polkadot.Init(coin.POLKADOT, config.Default.Polkadot.API),
+		coin.Stellar().Handle:      stellar.Init(coin.STELLAR, config.Default.Stellar.API),
+		coin.Cosmos().Handle:       cosmos.Init(coin.COSMOS, config.Default.Cosmos.API),
 		coin.Kava().Handle:         kava.Init(coin.KAVA, config.Default.Kava.API),
-		coin.Bitcoin().Handle:      bitcoin.Init(coin.BTC, config.Default.Bitcoin.API),
-		coin.Litecoin().Handle:     bitcoin.Init(coin.LTC, config.Default.Litecoin.API),
-		coin.Bitcoincash().Handle:  bitcoin.Init(coin.BCH, config.Default.Bitcoincash.API),
-		coin.Zcash().Handle:        bitcoin.Init(coin.ZEC, config.Default.Zcash.API),
-		coin.Zcoin().Handle:        bitcoin.Init(coin.FIRO, config.Default.Zcoin.API),
-		coin.Viacoin().Handle:      bitcoin.Init(coin.VIA, config.Default.Viacoin.API),
-		coin.Ravencoin().Handle:    bitcoin.Init(coin.RVN, config.Default.Ravencoin.API),
-		coin.Groestlcoin().Handle:  bitcoin.Init(coin.GRS, config.Default.Groestlcoin.API),
-		coin.Zelcash().Handle:      bitcoin.Init(coin.ZEL, config.Default.Zelcash.API),
-		coin.Decred().Handle:       bitcoin.Init(coin.DCR, config.Default.Decred.API),
-		coin.Digibyte().Handle:     bitcoin.Init(coin.DGB, config.Default.Digibyte.API),
+		coin.Bitcoin().Handle:      bitcoin.Init(coin.BITCOIN, config.Default.Bitcoin.API),
+		coin.Litecoin().Handle:     bitcoin.Init(coin.LITECOIN, config.Default.Litecoin.API),
+		coin.Bitcoincash().Handle:  bitcoin.Init(coin.BITCOINCASH, config.Default.Bitcoincash.API),
+		coin.Zcash().Handle:        bitcoin.Init(coin.ZCASH, config.Default.Zcash.API),
+		coin.Zcoin().Handle:        bitcoin.Init(coin.ZCOIN, config.Default.Zcoin.API),
+		coin.Viacoin().Handle:      bitcoin.Init(coin.VIACOIN, config.Default.Viacoin.API),
+		coin.Ravencoin().Handle:    bitcoin.Init(coin.RAVENCOIN, config.Default.Ravencoin.API),
+		coin.Groestlcoin().Handle:  bitcoin.Init(coin.GROESTLCOIN, config.Default.Groestlcoin.API),
+		coin.Zelcash().Handle:      bitcoin.Init(coin.ZELCASH, config.Default.Zelcash.API),
+		coin.Decred().Handle:       bitcoin.Init(coin.DECRED, config.Default.Decred.API),
+		coin.Digibyte().Handle:     bitcoin.Init(coin.DIGIBYTE, config.Default.Digibyte.API),
 		coin.Dash().Handle:         bitcoin.Init(coin.DASH, config.Default.Dash.API),
 		coin.Doge().Handle:         bitcoin.Init(coin.DOGE, config.Default.Doge.API),
 		coin.Qtum().Handle:         bitcoin.Init(coin.QTUM, config.Default.Qtum.API),
-		coin.Gochain().Handle:      ethereum.Init(coin.GO, config.Default.Gochain.API, config.Default.Gochain.RPC),
-		coin.Thundertoken().Handle: ethereum.Init(coin.TT, config.Default.Thundertoken.API, config.Default.Thundertoken.RPC),
-		coin.Classic().Handle:      ethereum.Init(coin.ETC, config.Default.Classic.API, config.Default.Classic.RPC),
-		coin.Poa().Handle:          ethereum.Init(coin.POA, config.Default.Poa.API, config.Default.Poa.RPC),
-		coin.Callisto().Handle:     ethereum.Init(coin.CLO, config.Default.Callisto.API, config.Default.Callisto.RPC),
-		coin.Wanchain().Handle:     ethereum.Init(coin.WAN, config.Default.Wanchain.API, config.Default.Wanchain.RPC),
-		coin.Tomochain().Handle:    ethereum.Init(coin.TOMO, config.Default.Tomochain.API, config.Default.Tomochain.RPC),
-		coin.Smartchain().Handle:   ethereum.InitWithBounce(coin.BSC, config.Default.Smartchain.RPC, config.Default.Smartchain.API, config.Default.Smartchain.CollectionsAPI),
-		coin.Ethereum().Handle:     ethereum.InitWithOpenSea(coin.ETH, config.Default.Ethereum.RPC, config.Default.Ethereum.BlockbookAPI, config.Default.Ethereum.CollectionsAPI, config.Default.Ethereum.CollectionsKey),
+		coin.Gochain().Handle:      ethereum.InitTrustRay(coin.GOCHAIN, config.Default.Gochain.API),
+		coin.Thundertoken().Handle: ethereum.InitTrustRay(coin.THUNDERTOKEN, config.Default.Thundertoken.API),
+		coin.Classic().Handle:      ethereum.InitTrustRay(coin.CLASSIC, config.Default.Classic.API),
+		coin.Poa().Handle:          ethereum.InitTrustRay(coin.POA, config.Default.Poa.API),
+		coin.Callisto().Handle:     ethereum.InitTrustRay(coin.CALLISTO, config.Default.Callisto.API),
+		coin.Wanchain().Handle:     ethereum.InitTrustRay(coin.WANCHAIN, config.Default.Wanchain.API),
+		coin.Tomochain().Handle:    ethereum.InitTrustRay(coin.TOMOCHAIN, config.Default.Tomochain.API),
+		coin.Smartchain().Handle:   ethereum.InitWithBounce(coin.SMARTCHAIN, config.Default.Smartchain.API, config.Default.Smartchain.CollectionsAPI),
+		coin.Ethereum().Handle:     ethereum.InitWithOpenSea(coin.ETHEREUM, config.Default.Ethereum.BlockbookAPI, config.Default.Ethereum.CollectionsAPI, config.Default.Ethereum.CollectionsKey),
 		coin.Near().Handle:         near.Init(config.Default.Near.API),
-		coin.Elrond().Handle:       elrond.Init(coin.EGLD, config.Default.Elrond.API),
+		coin.Elrond().Handle:       elrond.Init(coin.ELROND, config.Default.Elrond.API),
 		coin.Filecoin().Handle:     filecoin.Init(config.Default.Filecoin.API, config.Default.Filecoin.Explorer),
 	}
 }
 
 func getCollectionsHandlers() blockatlas.CollectionsAPIs {
 	return blockatlas.CollectionsAPIs{
-		coin.ETH: ethereum.InitWithOpenSea(coin.ETH, config.Default.Ethereum.RPC, config.Default.Ethereum.BlockbookAPI, config.Default.Ethereum.CollectionsAPI, config.Default.Ethereum.CollectionsKey),
+		coin.ETHEREUM:   ethereum.InitWithOpenSea(coin.ETHEREUM, config.Default.Ethereum.BlockbookAPI, config.Default.Ethereum.CollectionsAPI, config.Default.Ethereum.CollectionsKey),
+		coin.SMARTCHAIN: ethereum.InitWithBounce(coin.SMARTCHAIN, config.Default.Smartchain.API, config.Default.Smartchain.CollectionsAPI),
 	}
 }
diff --git a/platform/ripple/base.go b/platform/ripple/base.go
index 1c09c96..2f0111d 100644
--- a/platform/ripple/base.go
+++ b/platform/ripple/base.go
@@ -17,5 +17,5 @@ func Init(api string) *Platform {
 }
 
 func (p *Platform) Coin() coin.Coin {
-	return coin.Coins[coin.XRP]
+	return coin.Ripple()
 }
diff --git a/platform/ripple/transaction.go b/platform/ripple/transaction.go
index a8e5cae..2e6b17c 100644
--- a/platform/ripple/transaction.go
+++ b/platform/ripple/transaction.go
@@ -61,7 +61,7 @@ func NormalizeTx(srcTx *Tx) (types.Tx, bool) {
 
 	result := types.Tx{
 		ID:     srcTx.Hash,
-		Coin:   coin.XRP,
+		Coin:   coin.RIPPLE,
 		Date:   unix,
 		From:   srcTx.Payment.Account,
 		To:     srcTx.Payment.Destination,
@@ -70,8 +70,8 @@ func NormalizeTx(srcTx *Tx) (types.Tx, bool) {
 		Status: status,
 		Meta: types.Transfer{
 			Value:    types.Amount(v),
-			Symbol:   coin.Coins[coin.XRP].Symbol,
-			Decimals: coin.Coins[coin.XRP].Decimals,
+			Symbol:   coin.Coins[coin.RIPPLE].Symbol,
+			Decimals: coin.Coins[coin.RIPPLE].Decimals,
 		},
 	}
 	if srcTx.Payment.DestinationTag > 0 {
diff --git a/platform/solana/base.go b/platform/solana/base.go
index d693e29..cb1b403 100644
--- a/platform/solana/base.go
+++ b/platform/solana/base.go
@@ -18,5 +18,5 @@ func Init(api string) *Platform {
 }
 
 func (p *Platform) Coin() coin.Coin {
-	return coin.Coins[coin.SOL]
+	return coin.Solana()
 }
diff --git a/platform/tezos/base.go b/platform/tezos/base.go
index eee523d..b068208 100644
--- a/platform/tezos/base.go
+++ b/platform/tezos/base.go
@@ -23,5 +23,5 @@ func Init(api, rpc, baker string) *Platform {
 }
 
 func (p *Platform) Coin() coin.Coin {
-	return coin.Coins[coin.XTZ]
+	return coin.Tezos()
 }
diff --git a/platform/tezos/transaction.go b/platform/tezos/transaction.go
index f61a898..c781400 100644
--- a/platform/tezos/transaction.go
+++ b/platform/tezos/transaction.go
@@ -37,7 +37,7 @@ func NormalizeTx(srcTx Transaction, address string) (types.Tx, bool) {
 
 	tx = types.Tx{
 		Block:  srcTx.Height,
-		Coin:   coin.XTZ,
+		Coin:   coin.TEZOS,
 		Date:   srcTx.BlockTimestamp(),
 		Error:  srcTx.ErrorMsg(),
 		Fee:    types.Amount(numbers.DecimalExp(numbers.Float64toString(srcTx.Fee), 6)),
@@ -70,8 +70,8 @@ func NormalizeTx(srcTx Transaction, address string) (types.Tx, bool) {
 	case types.TxTransfer:
 		tx.Meta = types.Transfer{
 			Value:    value,
-			Symbol:   coin.Coins[coin.XTZ].Symbol,
-			Decimals: coin.Coins[coin.XTZ].Decimals,
+			Symbol:   coin.Tezos().Symbol,
+			Decimals: coin.Tezos().Decimals,
 		}
 	default:
 		return types.Tx{}, false
diff --git a/platform/tron/base.go b/platform/tron/base.go
index 71359f2..e29bc75 100644
--- a/platform/tron/base.go
+++ b/platform/tron/base.go
@@ -19,5 +19,5 @@ func Init(api, gridApi string) *Platform {
 }
 
 func (p *Platform) Coin() coin.Coin {
-	return coin.Coins[coin.TRX]
+	return coin.Tron()
 }
diff --git a/platform/tron/transaction.go b/platform/tron/transaction.go
index 8ee82b7..4702671 100644
--- a/platform/tron/transaction.go
+++ b/platform/tron/transaction.go
@@ -109,7 +109,7 @@ func normalizeTRC20Transactions(transactions TRC20Transactions) types.Txs {
 	for _, rawTx := range transactions.Data {
 		tx := types.Tx{
 			ID:     rawTx.TransactionID,
-			Coin:   coin.TRX,
+			Coin:   coin.TRON,
 			Date:   rawTx.BlockTimestamp / 1000,
 			From:   rawTx.From,
 			To:     rawTx.To,
@@ -153,7 +153,7 @@ func normalize(srcTx Tx) (*types.Tx, error) {
 
 	return &types.Tx{
 		ID:     srcTx.ID,
-		Coin:   coin.TRX,
+		Coin:   coin.TRON,
 		Date:   srcTx.BlockTime / 1000,
 		From:   from,
 		To:     to,
@@ -162,8 +162,8 @@ func normalize(srcTx Tx) (*types.Tx, error) {
 		Status: types.StatusCompleted,
 		Meta: types.Transfer{
 			Value:    transfer.Amount,
-			Symbol:   coin.Coins[coin.TRX].Symbol,
-			Decimals: coin.Coins[coin.TRX].Decimals,
+			Symbol:   coin.Tron().Symbol,
+			Decimals: coin.Tron().Decimals,
 		},
 	}, nil
 }
diff --git a/platform/vechain/base.go b/platform/vechain/base.go
index cd9a01e..17d2979 100644
--- a/platform/vechain/base.go
+++ b/platform/vechain/base.go
@@ -17,5 +17,5 @@ func Init(api string) *Platform {
 }
 
 func (p *Platform) Coin() coin.Coin {
-	return coin.Coins[coin.VET]
+	return coin.Vechain()
 }
diff --git a/platform/zilliqa/base.go b/platform/zilliqa/base.go
index 2e38134..0ebacba 100644
--- a/platform/zilliqa/base.go
+++ b/platform/zilliqa/base.go
@@ -21,5 +21,5 @@ func Init(api, apiKey, rpc string) *Platform {
 }
 
 func (p *Platform) Coin() coin.Coin {
-	return coin.Coins[coin.ZIL]
+	return coin.Zilliqa()
 }
diff --git a/platform/zilliqa/transaction.go b/platform/zilliqa/transaction.go
index 1ed5407..a2f7f79 100644
--- a/platform/zilliqa/transaction.go
+++ b/platform/zilliqa/transaction.go
@@ -27,7 +27,7 @@ func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) {
 func Normalize(srcTx *Tx) (tx types.Tx) {
 	tx = types.Tx{
 		ID:       srcTx.Hash,
-		Coin:     coin.ZIL,
+		Coin:     coin.ZILLIQA,
 		Date:     srcTx.Timestamp / 1000,
 		From:     srcTx.From,
 		To:       srcTx.To,
@@ -37,8 +37,8 @@ func Normalize(srcTx *Tx) (tx types.Tx) {
 		Sequence: srcTx.NonceValue(),
 		Meta: types.Transfer{
 			Value:    types.Amount(srcTx.Value),
-			Symbol:   coin.Coins[coin.ZIL].Symbol,
-			Decimals: coin.Coins[coin.ZIL].Decimals,
+			Symbol:   coin.Zilliqa().Symbol,
+			Decimals: coin.Zilliqa().Decimals,
 		},
 	}
 	if !srcTx.ReceiptSuccess {


Test patch:
diff --git a/platform/aeternity/transaction_test.go b/platform/aeternity/transaction_test.go
index e99d4e8..4d42e2f 100644
--- a/platform/aeternity/transaction_test.go
+++ b/platform/aeternity/transaction_test.go
@@ -27,7 +27,7 @@ func TestNormalizeTx(t *testing.T) {
 			},
 			wantTx: types.Tx{
 				ID:       "th_oJfBC6KZKaKsL4WXTq1ZtFiSE8Wp2PQYEnwyZqtudyHcU3Qg6",
-				Coin:     coin.AE,
+				Coin:     coin.AETERNITY,
 				From:     "ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv",
 				To:       "ak_ZWrS6xGhzxBasKmMbVSACfRioWqPyM5jNqMpBQ5ngP75RS6pS",
 				Fee:      "20500000000000",
diff --git a/platform/algorand/transaction_test.go b/platform/algorand/transaction_test.go
index a4eab9d..d9db60a 100644
--- a/platform/algorand/transaction_test.go
+++ b/platform/algorand/transaction_test.go
@@ -26,7 +26,7 @@ func TestNormalizeTx(t *testing.T) {
 			},
 			wantTx: types.Tx{
 				ID:     "C2LK3CGBPIGERLPFUXE6INSBJGHOXU7YZMEGELWMVSBASFJYOOQQ",
-				Coin:   coin.ALGO,
+				Coin:   coin.ALGORAND,
 				From:   "5TSQNIL54GB545B3WLC6OVH653SHAELMHU6MSVNGTUNMOEHAMWG7EC3AA4",
 				To:     "4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U",
 				Fee:    types.Amount("1000"),
diff --git a/platform/bitcoin/transaction_test.go b/platform/bitcoin/transaction_test.go
index 70329e9..6bbe064 100644
--- a/platform/bitcoin/transaction_test.go
+++ b/platform/bitcoin/transaction_test.go
@@ -21,7 +21,7 @@ var (
 
 	expectedOutgoingTx = types.Tx{
 		ID:   "df63ddab7d4eed2fb6cb40d4d0519e7e5ac7cf5ad556b2edbd45963ea1a2931c",
-		Coin: coin.BTC,
+		Coin: coin.BITCOIN,
 		From: "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC",
 		To:   "3FjBW1KL9L8aYtdKzJ8FhCNxmXB7dXDRw4",
 		Inputs: []types.TxOutput{
@@ -52,7 +52,7 @@ var (
 
 	expectedIncomingTx = types.Tx{
 		ID:   "a2d70bee124510c476f159fa83cdb34d663fc6020c81aad19b238601d679fed7",
-		Coin: coin.ZEC,
+		Coin: coin.ZCASH,
 		From: "t1T7cLkvDVScjw95WguoAZbbT8mrdqVtpiD",
 		To:   "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM",
 		Inputs: []types.TxOutput{
@@ -87,7 +87,7 @@ var (
 
 	expectedPendingTx = types.Tx{
 		ID:   "a2d70bee124510c476f159fa83cdb34d663fc6020c81aad19b238601d679fed7",
-		Coin: coin.ZEC,
+		Coin: coin.ZCASH,
 		From: "t1T7cLkvDVScjw95WguoAZbbT8mrdqVtpiD",
 		To:   "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM",
 		Inputs: []types.TxOutput{
diff --git a/platform/cosmos/transaction_test.go b/platform/cosmos/transaction_test.go
index d0355aa..e55f711 100644
--- a/platform/cosmos/transaction_test.go
+++ b/platform/cosmos/transaction_test.go
@@ -20,9 +20,12 @@ var (
 	claimRewardSrc1, _   = mock.JsonStringFromFilePath("mocks/" + "claim_1.json")
 	claimRewardSrc2, _   = mock.JsonStringFromFilePath("mocks/" + "claim_2.json")
 
+	atom = coin.Cosmos()
+	kava = coin.Kava()
+
 	transferDst = types.Tx{
 		ID:     "E19B011D20D862DA0BEA7F24E3BC6DFF666EE6E044FCD9BD95B073478086DBB6",
-		Coin:   coin.ATOM,
+		Coin:   atom.ID,
 		From:   "cosmos1rw62phusuv9vzraezr55k0vsqssvz6ed52zyrl",
 		To:     "cosmos1nynns8ex9fq6sjjfj8k79ymkdz4sqth06xexae",
 		Fee:    "1",
@@ -39,7 +42,7 @@ var (
 
 	transferDstKava = types.Tx{
 		ID:     "E19B011D20D862DA0BEA7F24E3BC6DFF666EE6E044FCD9BD95B073478086DBB6",
-		Coin:   coin.KAVA,
+		Coin:   kava.ID,
 		From:   "kava17wcggpjx007uc09s8y4hwrj8f228mlwe0n0upn",
 		To:     "kava1z89utvygweg5l56fsk8ak7t6hh88fd0agl98n0",
 		Fee:    "1",
@@ -49,14 +52,14 @@ var (
 		Type:   types.TxTransfer,
 		Meta: types.Transfer{
 			Value:    "2271999999",
-			Symbol:   coin.Kava().Symbol,
+			Symbol:   kava.Symbol,
 			Decimals: 6,
 		},
 	}
 
 	delegateDst = types.Tx{
 		ID:        "11078091D1D5BD84F4275B6CEE02170428944DB0E8EEC37E980551435F6D04C7",
-		Coin:      coin.ATOM,
+		Coin:      atom.ID,
 		From:      "cosmos1237l0vauhw78qtwq045jd24ay4urpec6r3xfn3",
 		To:        "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2",
 		Fee:       "5000",
@@ -66,19 +69,19 @@ var (
 		Type:      types.TxAnyAction,
 		Direction: types.DirectionOutgoing,
 		Meta: types.AnyAction{
-			Coin:     coin.ATOM,
+			Coin:     atom.ID,
 			Title:    types.AnyActionDelegation,
 			Key:      types.KeyStakeDelegate,
-			Name:     coin.Cosmos().Name,
-			Symbol:   coin.Coins[coin.ATOM].Symbol,
-			Decimals: coin.Coins[coin.ATOM].Decimals,
+			Name:     atom.Name,
+			Symbol:   atom.Symbol,
+			Decimals: atom.Decimals,
 			Value:    "49920",
 		},
 	}
 
 	unDelegateDst = types.Tx{
 		ID:        "A1EC36741FEF681F4A77B8F6032AD081100EE5ECB4CC76AEAC2174BC6B871CFE",
-		Coin:      coin.ATOM,
+		Coin:      atom.ID,
 		From:      "cosmos137rrp4p8n0nqcft0mwc62tdnyhhzf80knv5t94",
 		To:        "cosmosvaloper1te8nxpc2myjfrhaty0dnzdhs5ahdh5agzuym9v",
 		Fee:       "5000",
@@ -88,19 +91,19 @@ var (
 		Type:      types.TxAnyAction,
 		Direction: types.DirectionIncoming,
 		Meta: types.AnyAction{
-			Coin:     coin.ATOM,
+			Coin:     atom.ID,
 			Title:    types.AnyActionUndelegation,
 			Key:      types.KeyStakeDelegate,
-			Name:     coin.Cosmos().Name,
-			Symbol:   coin.Coins[coin.ATOM].Symbol,
-			Decimals: coin.Coins[coin.ATOM].Decimals,
+			Name:     atom.Name,
+			Symbol:   atom.Symbol,
+			Decimals: atom.Decimals,
 			Value:    "5100000000",
 		},
 	}
 
 	claimRewardDst2 = types.Tx{
 		ID:        "082BA88EC055A7C343A353297EAC104CE87C659E0DDD84621C9AC3C284232800",
-		Coin:      coin.ATOM,
+		Coin:      atom.ID,
 		From:      "cosmos1y6yvdel7zys8x60gz9067fjpcpygsn62ae9x46",
 		To:        "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2",
 		Fee:       "0",
@@ -111,19 +114,19 @@ var (
 		Direction: types.DirectionIncoming,
 		Memo:      "复投",
 		Meta: types.AnyAction{
-			Coin:     coin.ATOM,
+			Coin:     atom.ID,
 			Title:    types.AnyActionClaimRewards,
 			Key:      types.KeyStakeClaimRewards,
-			Name:     coin.Cosmos().Name,
-			Symbol:   coin.Coins[coin.ATOM].Symbol,
-			Decimals: coin.Coins[coin.ATOM].Decimals,
+			Name:     atom.Name,
+			Symbol:   atom.Symbol,
+			Decimals: atom.Decimals,
 			Value:    "2692701",
 		},
 	}
 
 	claimRewardDst1 = types.Tx{
 		ID:        "C382DCFDC30E2DA294421DAEAD5862F118592A7B000EE91F6BEF8452A1F525D7",
-		Coin:      coin.ATOM,
+		Coin:      atom.ID,
 		From:      "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug",
 		To:        "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5",
 		Fee:       "1000",
@@ -134,19 +137,19 @@ var (
 		Direction: types.DirectionIncoming,
 		Memo:      "",
 		Meta: types.AnyAction{
-			Coin:     coin.ATOM,
+			Coin:     atom.ID,
 			Title:    types.AnyActionClaimRewards,
 			Key:      types.KeyStakeClaimRewards,
-			Name:     coin.Cosmos().Name,
-			Symbol:   coin.Coins[coin.ATOM].Symbol,
-			Decimals: coin.Coins[coin.ATOM].Decimals,
+			Name:     atom.Name,
+			Symbol:   atom.Symbol,
+			Decimals: atom.Decimals,
 			Value:    "86278",
 		},
 	}
 
 	failedTransferDst = types.Tx{
 		ID:     "5E78C65A8C1A6C8239EBBBBF2E42020E6ADBA8037EDEA83BF88E1A9159CF13B8",
-		Coin:   coin.ATOM,
+		Coin:   atom.ID,
 		From:   "cosmos1shpfyt7psrff2ux7nznxvj6f7gq59fcqng5mku",
 		To:     "cosmos1za4pu5gxm80fg6sx0956f88l2sx7jfg2vf7nlc",
 		Fee:    "2000",
@@ -172,7 +175,7 @@ type test struct {
 
 func TestNormalize(t *testing.T) {
 
-	cosmos := Platform{CoinIndex: coin.ATOM}
+	cosmos := Platform{CoinIndex: atom.ID}
 	kava := Platform{CoinIndex: coin.KAVA}
 
 	tests := []test{
diff --git a/platform/elrond/transaction_test.go b/platform/elrond/transaction_test.go
index 0d67181..6405de9 100644
--- a/platform/elrond/transaction_test.go
+++ b/platform/elrond/transaction_test.go
@@ -22,7 +22,7 @@ var (
 
 	txTransfer1Normalized = types.Tx{
 		ID:       "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df",
-		Coin:     coin.EGLD,
+		Coin:     coin.ELROND,
 		Date:     int64(1587715632),
 		From:     "metachain",
 		To:       "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0",
@@ -40,7 +40,7 @@ var (
 
 	txTransfer2Normalized = types.Tx{
 		ID:       "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df",
-		Coin:     coin.EGLD,
+		Coin:     coin.ELROND,
 		Date:     int64(1588757256),
 		From:     "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0",
 		To:       "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0",
@@ -58,7 +58,7 @@ var (
 
 	txTransfer3Normalized = types.Tx{
 		ID:       "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df",
-		Coin:     coin.EGLD,
+		Coin:     coin.ELROND,
 		Date:     int64(1588757256),
 		From:     "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0",
 		To:       "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y",
@@ -76,7 +76,7 @@ var (
 
 	txTransfer4Normalized = types.Tx{
 		ID:       "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df",
-		Coin:     coin.EGLD,
+		Coin:     coin.ELROND,
 		Date:     int64(1588757256),
 		From:     "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0",
 		To:       "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y",
@@ -94,7 +94,7 @@ var (
 
 	txTransfer5Normalized = types.Tx{
 		ID:       "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df",
-		Coin:     coin.EGLD,
+		Coin:     coin.ELROND,
 		Date:     int64(1588757256),
 		From:     "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0",
 		To:       "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y",
@@ -112,7 +112,7 @@ var (
 
 	txTransfer6Normalized = types.Tx{
 		ID:       "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df",
-		Coin:     coin.EGLD,
+		Coin:     coin.ELROND,
 		From:     "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0",
 		To:       "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y",
 		Fee:      "5000",
diff --git a/platform/ethereum/bounce/client_test.go b/platform/ethereum/bounce/client_test.go
new file mode 100644
index 0000000..96182f2
--- /dev/null
+++ b/platform/ethereum/bounce/client_test.go
@@ -0,0 +1,31 @@
+package bounce
+
+import (
+	"testing"
+)
+
+func Test_normalizeUrl(t *testing.T) {
+	tests := []struct {
+		name string
+		uri  string
+		want string
+	}{
+		{
+			name: "Test pancake bunny token uri",
+			uri:  "ipfs://QmYu9WwPNKNSZQiTCDfRk7aCR472GURavR9M1qosDmqpev/swapsies.json",
+			want: "https://ipfs.io/ipfs/QmYu9WwPNKNSZQiTCDfRk7aCR472GURavR9M1qosDmqpev/swapsies.json",
+		},
+		{
+			name: "Test url with ipfs prefix",
+			uri:  "ipfs://ipfs/QmS3hmJqpHpvnCocqv9FTZbcSGDnvuFv4qWY3qnwkMpB9x",
+			want: "https://ipfs.io/ipfs/QmS3hmJqpHpvnCocqv9FTZbcSGDnvuFv4qWY3qnwkMpB9x",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := normalizeUrl(tt.uri); got != tt.want {
+				t.Errorf("normalizeUrl() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/platform/ethereum/bounce/collection_test.go b/platform/ethereum/bounce/collection_test.go
new file mode 100644
index 0000000..a7da964
--- /dev/null
+++ b/platform/ethereum/bounce/collection_test.go
@@ -0,0 +1,87 @@
+package bounce
+
+import (
+	"reflect"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/trustwallet/golibs/coin"
+	"github.com/trustwallet/golibs/mock"
+	"github.com/trustwallet/golibs/types"
+)
+
+func Test_normalizeCollectible(t *testing.T) {
+	type args struct {
+		filename  string
+		coinIndex uint
+		info      CollectionInfo
+	}
+	tests := []struct {
+		name string
+		args args
+		want types.Collectible
+	}{
+		{
+			name: "Test empty contract name",
+			args: args{
+				filename:  "artwork_nft.json",
+				coinIndex: coin.SMARTCHAIN,
+				info: CollectionInfo{
+					Name:        "Hungry",
+					Description: "Animal Series",
+					Image:       "https://d3ggs2vjn5heyw.cloudfront.net/static/nfts/artworks/d9dc679ec0614eb78b479aed21694305.jpg",
+				},
+			},
+			want: types.Collectible{
+				ID:              "0x5Bc94e9347F3b9Be8415bDfd24af16666704E44f-450",
+				CollectionID:    "0x5Bc94e9347F3b9Be8415bDfd24af16666704E44f",
+				TokenID:         "450",
+				ContractAddress: "0x5Bc94e9347F3b9Be8415bDfd24af16666704E44f",
+				Category:        "Hungry",
+				ImageUrl:        "https://d3ggs2vjn5heyw.cloudfront.net/static/nfts/artworks/d9dc679ec0614eb78b479aed21694305.jpg",
+				ExternalLink:    "https://www.bakeryswap.org/api/v1/artworks/fb4576253e3d45cebf0ac4c8df8f1743",
+				Type:            string(types.ERC721),
+				Description:     "Animal Series",
+				Coin:            coin.SMARTCHAIN,
+				Name:            "Hungry",
+				Version:         "3.0",
+			},
+		},
+		{
+			name: "Test pancake bunny",
+			args: args{
+				filename:  "pancake_bunny.json",
+				coinIndex: coin.SMARTCHAIN,
+				info: CollectionInfo{
+					Name:        "Swapsies",
+					Description: "These bunnies love nothing more than swapping pancakes. Especially on BSC.",
+					Image:       "https://ipfs.io/ipfs/QmXdHqg3nywpNJWDevJQPtkz93vpfoHcZWQovFz2nmtPf5/swapsies.png",
+				},
+			},
+			want: types.Collectible{
+				ID:              "0xDf7952B35f24aCF7fC0487D01c8d5690a60DBa07-409",
+				CollectionID:    "0xDf7952B35f24aCF7fC0487D01c8d5690a60DBa07",
+				TokenID:         "409",
+				ContractAddress: "0xDf7952B35f24aCF7fC0487D01c8d5690a60DBa07",
+				Category:        "Pancake Bunnies",
+				ImageUrl:        "https://ipfs.io/ipfs/QmXdHqg3nywpNJWDevJQPtkz93vpfoHcZWQovFz2nmtPf5/swapsies.png",
+				ExternalLink:    "https://ipfs.io/ipfs/QmYu9WwPNKNSZQiTCDfRk7aCR472GURavR9M1qosDmqpev/swapsies.json",
+				Type:            string(types.ERC721),
+				Description:     "These bunnies love nothing more than swapping pancakes. Especially on BSC.",
+				Coin:            coin.SMARTCHAIN,
+				Name:            "Swapsies",
+				Version:         "3.0",
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			var c Collectible
+			err := mock.JsonModelFromFilePath("mocks/"+tt.args.filename, &c)
+			assert.Nil(t, err)
+			if got := normalizeCollectible(c, tt.args.coinIndex, tt.args.info); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("normalizeCollectible() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/platform/ethereum/opensea/collection_test.go b/platform/ethereum/opensea/collection_test.go
index 5524bbf..494842e 100644
--- a/platform/ethereum/opensea/collection_test.go
+++ b/platform/ethereum/opensea/collection_test.go
@@ -68,7 +68,7 @@ func TestNormalizeCollectionV4(t *testing.T) {
 	var collections []Collection
 	err := json.Unmarshal([]byte(collectionsSrcV4), &collections)
 	assert.Nil(t, err)
-	page := NormalizeCollections(collections, coin.ETH, collectionsOwnerV4)
+	page := NormalizeCollections(collections, coin.ETHEREUM, collectionsOwnerV4)
 	assert.Equal(t, 3, len(page), "collections could not be normalized")
 	expected := types.CollectionPage{collection1DstV4, collection2DstV4, collection3DstV4}
 	assert.Equal(t, page, expected, "collections don't equal")
@@ -78,7 +78,7 @@ func TestNormalizeCollectibleV4(t *testing.T) {
 	var collectibles []Collectible
 	err := json.Unmarshal([]byte(collectibleSrcV4), &collectibles)
 	assert.Nil(t, err)
-	page := NormalizeCollectiblePage(collectibles, coin.ETH)
+	page := NormalizeCollectiblePage(collectibles, coin.ETHEREUM)
 	assert.Equal(t, len(page), 1, "collectible could not be normalized")
 	expected := types.CollectiblePage{collectibleDstV4}
 	assert.Equal(t, page, expected, "collectible don't equal")
diff --git a/platform/ethereum/trustray/token_test.go b/platform/ethereum/trustray/token_test.go
index 85ea3ff..aea1f8c 100644
--- a/platform/ethereum/trustray/token_test.go
+++ b/platform/ethereum/trustray/token_test.go
@@ -34,61 +34,61 @@ func TestNormalizeToken(t *testing.T) {
 		{
 			"ethereum erc20",
 			tokenSrc,
-			coin.ETH,
+			coin.ETHEREUM,
 			types.Token{
 				Name:     "FusChain",
 				Symbol:   "FUS",
 				Decimals: 18,
 				TokenID:  "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A",
-				Coin:     coin.ETH,
+				Coin:     coin.ETHEREUM,
 				Type:     types.ERC20,
 			},
 		},
 		{"classic etc20",
 			tokenSrc,
-			coin.ETC,
+			coin.CLASSIC,
 			types.Token{
 				Name:     "FusChain",
 				Symbol:   "FUS",
 				Decimals: 18,
 				TokenID:  "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A",
-				Coin:     coin.ETC,
+				Coin:     coin.CLASSIC,
 				Type:     types.ETC20,
 			},
 		},
 		{"gochain go20",
 			tokenSrc,
-			coin.GO,
+			coin.GOCHAIN,
 			types.Token{
 				Name:     "FusChain",
 				Symbol:   "FUS",
 				Decimals: 18,
 				TokenID:  "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A",
-				Coin:     coin.GO,
+				Coin:     coin.GOCHAIN,
 				Type:     types.GO20,
 			},
 		},
 		{"thudertoken tt20",
 			tokenSrc,
-			coin.TT,
+			coin.THUNDERTOKEN,
 			types.Token{
 				Name:     "FusChain",
 				Symbol:   "FUS",
 				Decimals: 18,
 				TokenID:  "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A",
-				Coin:     coin.TT,
+				Coin:     coin.THUNDERTOKEN,
 				Type:     types.TT20,
 			},
 		},
 		{"wanchain wan20",
 			tokenSrc,
-			coin.WAN,
+			coin.WANCHAIN,
 			types.Token{
 				Name:     "FusChain",
 				Symbol:   "FUS",
 				Decimals: 18,
 				TokenID:  "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A",
-				Coin:     coin.WAN,
+				Coin:     coin.WANCHAIN,
 				Type:     types.WAN20,
 			},
 		},
@@ -106,13 +106,13 @@ func TestNormalizeToken(t *testing.T) {
 		},
 		{"callisto clo20",
 			tokenSrc,
-			coin.CLO,
+			coin.CALLISTO,
 			types.Token{
 				Name:     "FusChain",
 				Symbol:   "FUS",
 				Decimals: 18,
 				TokenID:  "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A",
-				Coin:     coin.CLO,
+				Coin:     coin.CALLISTO,
 				Type:     types.CLO20,
 			},
 		},
diff --git a/platform/ethereum/trustray/transaction_test.go b/platform/ethereum/trustray/transaction_test.go
index 5f2ea02..4aec0ed 100644
--- a/platform/ethereum/trustray/transaction_test.go
+++ b/platform/ethereum/trustray/transaction_test.go
@@ -116,7 +116,7 @@ var (
 )
 var tokenTransferDst = types.Tx{
 	ID:       "0x7777854580f273df61e0162e1a41b3e1e05ab8b9f553036fa9329a90dd7e9ab2",
-	Coin:     coin.ETH,
+	Coin:     coin.ETHEREUM,
 	From:     addr1,
 	To:       contract1,
 	Fee:      "358254913291776",
@@ -137,7 +137,7 @@ var tokenTransferDst = types.Tx{
 
 var contractCallDst = types.Tx{
 	ID:       "0x34ab0028a9aa794d5cc12887e7b813cec17889948276b301028f24a408da6da4",
-	Coin:     coin.ETH,
+	Coin:     coin.ETHEREUM,
 	From:     "0xc9a16a82c284EFC3cB0fE8C891ab85d6EBa0EeFB",
 	To:       "0xc67f9C909C4d185E4A5d21D642c27D05A145a76c",
 	Fee:      "42680000000000",
@@ -153,7 +153,7 @@ var contractCallDst = types.Tx{
 
 var transferDst = types.Tx{
 	ID:       "0x77f8a3b2203933493d103a1637de814b4853410b1fb2981c4d2cff4d7a3071ab",
-	Coin:     coin.ETH,
+	Coin:     coin.ETHEREUM,
 	From:     "0xf5AeA47E57c058881B31EE8fcE1002C409188F06",
 	To:       "0x0Ae933A89D9E249D0873cfc7CA022fCB3F1280Ce",
 	Fee:      "105000000000000",
@@ -170,7 +170,7 @@ var transferDst = types.Tx{
 
 var failedDst = types.Tx{
 	ID:       "0x8dfe7e859f7bdcea4e6f4ada18567d96a51c3aa29e618ef09b80ae99385e191e",
-	Coin:     coin.ETH,
+	Coin:     coin.ETHEREUM,
 	From:     "0x4b55af7cE28A113D794F9A9940fe1506f37aA619",
 	To:       "0xE65f787c8561A4b15771111bb427274deDfe85D7",
 	Fee:      "63000000000000",
@@ -207,7 +207,7 @@ func TestNormalize(t *testing.T) {
 				t.Error(err)
 				return
 			}
-			res := AppendTxs(nil, &doc, coin.ETH)
+			res := AppendTxs(nil, &doc, coin.ETHEREUM)
 
 			resJSON, err := json.Marshal(res)
 			if err != nil {
diff --git a/platform/harmony/transaction_test.go b/platform/harmony/transaction_test.go
index 73f16ee..d9c524d 100644
--- a/platform/harmony/transaction_test.go
+++ b/platform/harmony/transaction_test.go
@@ -27,7 +27,7 @@ func TestNormalizeTx(t *testing.T) {
 			},
 			wantTx: types.Tx{
 				ID:     "0x230798fe22abff459b004675bf827a4089326a296fa4165d0c2ad27688e03e0c",
-				Coin:   coin.ONE,
+				Coin:   coin.HARMONY,
 				From:   "one103q7qe5t2505lypvltkqtddaef5tzfxwsse4z7",
 				To:     "one129r9pj3sk0re76f7zs3qz92rggmdgjhtwge62k",
 				Fee:    "21000000000000",
diff --git a/platform/icon/transaction_test.go b/platform/icon/transaction_test.go
index b5ea3ad..583ecba 100644
--- a/platform/icon/transaction_test.go
+++ b/platform/icon/transaction_test.go
@@ -26,7 +26,7 @@ func TestNormalizeTx(t *testing.T) {
 			},
 			wantTx: types.Tx{
 				ID:     "0x34b8b6ec3a52710c24074f5e298f4a9c67bb61a0a1dde20e695efaeb30ff3754",
-				Coin:   coin.ICX,
+				Coin:   coin.ICON,
 				From:   "hx1b8959dd5c57d2c502e22ee0a887d33baec09091",
 				To:     "cx334db6519871cb2bfd154cec0905ced4ea142de1",
 				Fee:    "1747600000000000",
diff --git a/platform/iotex/transaction_test.go b/platform/iotex/transaction_test.go
index fb51f53..66faf0e 100644
--- a/platform/iotex/transaction_test.go
+++ b/platform/iotex/transaction_test.go
@@ -26,7 +26,7 @@ func TestNormalize(t *testing.T) {
 			want: []*types.Tx{
 				{
 					ID:       "109b75cb688a5347268cbf11b20fa90fd0a14e92a42ba735c046bbf1a6e66ad7",
-					Coin:     coin.IOTX,
+					Coin:     coin.IOTEX,
 					From:     "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m",
 					To:       "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m",
 					Fee:      types.Amount("10000000000000000"),
diff --git a/platform/kava/transaction_test.go b/platform/kava/transaction_test.go
index 872b18f..d2d9a2c 100644
--- a/platform/kava/transaction_test.go
+++ b/platform/kava/transaction_test.go
@@ -626,7 +626,7 @@ const claimRewardSrc2 = `
 
 var transferDst = types.Tx{
 	ID:     "E19B011D20D862DA0BEA7F24E3BC6DFF666EE6E044FCD9BD95B073478086DBB6",
-	Coin:   coin.ATOM,
+	Coin:   coin.COSMOS,
 	From:   "cosmos1rw62phusuv9vzraezr55k0vsqssvz6ed52zyrl",
 	To:     "cosmos1nynns8ex9fq6sjjfj8k79ymkdz4sqth06xexae",
 	Fee:    "1",
@@ -681,7 +681,7 @@ var transferDstKavaToken = types.Tx{
 
 var delegateDst = types.Tx{
 	ID:        "11078091D1D5BD84F4275B6CEE02170428944DB0E8EEC37E980551435F6D04C7",
-	Coin:      coin.ATOM,
+	Coin:      coin.COSMOS,
 	From:      "cosmos1237l0vauhw78qtwq045jd24ay4urpec6r3xfn3",
 	To:        "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2",
 	Fee:       "5000",
@@ -691,19 +691,19 @@ var delegateDst = types.Tx{
 	Type:      types.TxAnyAction,
 	Direction: types.DirectionOutgoing,
 	Meta: types.AnyAction{
-		Coin:     coin.ATOM,
+		Coin:     coin.COSMOS,
 		Title:    types.AnyActionDelegation,
 		Key:      types.KeyStakeDelegate,
 		Name:     coin.Cosmos().Name,
-		Symbol:   coin.Coins[coin.ATOM].Symbol,
-		Decimals: coin.Coins[coin.ATOM].Decimals,
+		Symbol:   coin.Coins[coin.COSMOS].Symbol,
+		Decimals: coin.Coins[coin.COSMOS].Decimals,
 		Value:    "49920",
 	},
 }
 
 var unDelegateDst = types.Tx{
 	ID:        "A1EC36741FEF681F4A77B8F6032AD081100EE5ECB4CC76AEAC2174BC6B871CFE",
-	Coin:      coin.ATOM,
+	Coin:      coin.COSMOS,
 	From:      "cosmos137rrp4p8n0nqcft0mwc62tdnyhhzf80knv5t94",
 	To:        "cosmosvaloper1te8nxpc2myjfrhaty0dnzdhs5ahdh5agzuym9v",
 	Fee:       "5000",
@@ -713,19 +713,19 @@ var unDelegateDst = types.Tx{
 	Type:      types.TxAnyAction,
 	Direction: types.DirectionIncoming,
 	Meta: types.AnyAction{
-		Coin:     coin.ATOM,
+		Coin:     coin.COSMOS,
 		Title:    types.AnyActionUndelegation,
 		Key:      types.KeyStakeDelegate,
 		Name:     coin.Cosmos().Name,
-		Symbol:   coin.Coins[coin.ATOM].Symbol,
-		Decimals: coin.Coins[coin.ATOM].Decimals,
+		Symbol:   coin.Coins[coin.COSMOS].Symbol,
+		Decimals: coin.Coins[coin.COSMOS].Decimals,
 		Value:    "5100000000",
 	},
 }
 
 var claimRewardDst2 = types.Tx{
 	ID:        "082BA88EC055A7C343A353297EAC104CE87C659E0DDD84621C9AC3C284232800",
-	Coin:      coin.ATOM,
+	Coin:      coin.COSMOS,
 	From:      "cosmos1y6yvdel7zys8x60gz9067fjpcpygsn62ae9x46",
 	To:        "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2",
 	Fee:       "0",
@@ -736,19 +736,19 @@ var claimRewardDst2 = types.Tx{
 	Direction: types.DirectionIncoming,
 	Memo:      "复投",
 	Meta: types.AnyAction{
-		Coin:     coin.ATOM,
+		Coin:     coin.COSMOS,
 		Title:    types.AnyActionClaimRewards,
 		Key:      types.KeyStakeClaimRewards,
 		Name:     coin.Cosmos().Name,
-		Symbol:   coin.Coins[coin.ATOM].Symbol,
-		Decimals: coin.Coins[coin.ATOM].Decimals,
+		Symbol:   coin.Coins[coin.COSMOS].Symbol,
+		Decimals: coin.Coins[coin.COSMOS].Decimals,
 		Value:    "2692701",
 	},
 }
 
 var claimRewardDst1 = types.Tx{
 	ID:        "C382DCFDC30E2DA294421DAEAD5862F118592A7B000EE91F6BEF8452A1F525D7",
-	Coin:      coin.ATOM,
+	Coin:      coin.COSMOS,
 	From:      "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug",
 	To:        "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5",
 	Fee:       "1000",
@@ -759,19 +759,19 @@ var claimRewardDst1 = types.Tx{
 	Direction: types.DirectionIncoming,
 	Memo:      "",
 	Meta: types.AnyAction{
-		Coin:     coin.ATOM,
+		Coin:     coin.COSMOS,
 		Title:    types.AnyActionClaimRewards,
 		Key:      types.KeyStakeClaimRewards,
 		Name:     coin.Cosmos().Name,
-		Symbol:   coin.Coins[coin.ATOM].Symbol,
-		Decimals: coin.Coins[coin.ATOM].Decimals,
+		Symbol:   coin.Coins[coin.COSMOS].Symbol,
+		Decimals: coin.Coins[coin.COSMOS].Decimals,
 		Value:    "86278",
 	},
 }
 
 var failedTransferDst = types.Tx{
 	ID:     "5E78C65A8C1A6C8239EBBBBF2E42020E6ADBA8037EDEA83BF88E1A9159CF13B8",
-	Coin:   coin.ATOM,
+	Coin:   coin.COSMOS,
 	From:   "cosmos1shpfyt7psrff2ux7nznxvj6f7gq59fcqng5mku",
 	To:     "cosmos1za4pu5gxm80fg6sx0956f88l2sx7jfg2vf7nlc",
 	Fee:    "2000",
@@ -803,7 +803,7 @@ type filterTest struct {
 
 func TestNormalize(t *testing.T) {
 
-	cosmos := Platform{CoinIndex: coin.ATOM}
+	cosmos := Platform{CoinIndex: coin.COSMOS}
 	kava := Platform{CoinIndex: coin.KAVA}
 
 	tests := []test{
diff --git a/platform/nebulas/transaction_test.go b/platform/nebulas/transaction_test.go
index 92a6e4e..f59eebd 100644
--- a/platform/nebulas/transaction_test.go
+++ b/platform/nebulas/transaction_test.go
@@ -25,7 +25,7 @@ func TestNormalizeTx(t *testing.T) {
 			},
 			wantTx: types.Tx{
 				ID:       "96bd280d60447b7dbcdb3fa76a99856e0422a76304e9d01d0c87e1dfceb6d952",
-				Coin:     coin.NAS,
+				Coin:     coin.NEBULAS,
 				From:     "n1Yv9xJJcH4UjoJPVDGdUCL2CxK29asFuyV",
 				To:       "n1TFrmLUDTe5ggQaWJiXHSqNSRzKYdaV6hQ",
 				Fee:      "400000000000000",
diff --git a/platform/nimiq/transaction_test.go b/platform/nimiq/transaction_test.go
index 8ab4264..f9a2709 100644
--- a/platform/nimiq/transaction_test.go
+++ b/platform/nimiq/transaction_test.go
@@ -19,7 +19,7 @@ var (
 	pendingSrc, _ = mock.JsonStringFromFilePath("mocks/" + "pending_tx.json")
 	basicDst      = types.Tx{
 		ID:    "8b219949f4c1dfe9e7a9cdc5dbbc507e40dc16f44a1a5182ed6125c9a6891a50",
-		Coin:  coin.NIM,
+		Coin:  coin.NIMIQ,
 		From:  "NQ69 9A4A MB83 HXDQ 4J46 BH5R 4JFF QMA9 C3GN",
 		To:    "NQ15 MLJN 23YB 8FBM 61TN 7LYG 2212 LVBG 4V19",
 		Fee:   "138",
@@ -33,7 +33,7 @@ var (
 	}
 	pendingDst = types.Tx{
 		ID:    "79719d16f3f347cc98c35cd7a9af708cdce97de578b5135c5ae4393fd7920d61",
-		Coin:  coin.NIM,
+		Coin:  coin.NIMIQ,
 		From:  "NQ74 SJ0Q 49T1 4XQL KABH 1RUC 8DPT 9F0U 9P0B",
 		To:    "NQ97 18BJ 33YV QGHQ BV2K 56V4 12CH J8TD S9S3",
 		Fee:   "300",
diff --git a/platform/ontology/transaction_test.go b/platform/ontology/transaction_test.go
index 44c0587..e385dcf 100644
--- a/platform/ontology/transaction_test.go
+++ b/platform/ontology/transaction_test.go
@@ -18,7 +18,7 @@ var (
 
 	dstOntTransfer = types.Tx{
 		ID:     "ea0e5d8e389cb96760887094194ca359ac998b2f607be470a576861b91e2bf52",
-		Coin:   coin.ONT,
+		Coin:   coin.ONTOLOGY,
 		From:   "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij",
 		To:     "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij",
 		Fee:    "10000000",
@@ -34,7 +34,7 @@ var (
 	}
 	dstOngTransfer = types.Tx{
 		ID:     "e5946ba02f56e17c3709db2bc91f43f76ee3a359006586024daa5c4ad8c54e78",
-		Coin:   coin.ONT,
+		Coin:   coin.ONTOLOGY,
 		From:   "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx",
 		To:     "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij",
 		Fee:    "10000000",
@@ -54,7 +54,7 @@ var (
 	}
 	dstRewardTransfer = types.Tx{
 		ID:     "d7554dcdf01f394b9107ff598df6d84e4c3b00ccf1e720b8c09abf085cbe4987",
-		Coin:   coin.ONT,
+		Coin:   coin.ONTOLOGY,
 		From:   "AFmseVrdL9f9oyCzZefL9tG6UbvhUMqNMV",
 		To:     "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij",
 		Fee:    "10000000",
diff --git a/platform/polkadot/transaction_test.go b/platform/polkadot/transaction_test.go
index 10195d8..37bab42 100644
--- a/platform/polkadot/transaction_test.go
+++ b/platform/polkadot/transaction_test.go
@@ -9,7 +9,7 @@ import (
 )
 
 func TestNormalizeTransfer(t *testing.T) {
-	platform := Platform{CoinIndex: coin.KSM}
+	platform := Platform{CoinIndex: coin.KUSAMA}
 	type args struct {
 		srcTx *Transfer
 	}
@@ -101,7 +101,7 @@ func TestNormalizeExtrinsic(t *testing.T) {
 		{
 			name: "Transfer KSM",
 			args: args{
-				platform: Platform{CoinIndex: coin.KSM},
+				platform: Platform{CoinIndex: coin.KUSAMA},
 				srcTx: &Extrinsic{
 					Timestamp:          1577176992,
 					BlockNumber:        360298,
@@ -135,7 +135,7 @@ func TestNormalizeExtrinsic(t *testing.T) {
 		{
 			name: "Transfer DOT",
 			args: args{
-				platform: Platform{CoinIndex: coin.DOT},
+				platform: Platform{CoinIndex: coin.POLKADOT},
 				srcTx: &Extrinsic{
 					Timestamp:          1607035338,
 					BlockNumber:        2742892,
@@ -169,7 +169,7 @@ func TestNormalizeExtrinsic(t *testing.T) {
 		{
 			name: "Bond",
 			args: args{
-				platform: Platform{CoinIndex: coin.KSM},
+				platform: Platform{CoinIndex: coin.KUSAMA},
 				srcTx: &Extrinsic{
 					Timestamp:          1577712822,
 					BlockNumber:        447444,
@@ -187,7 +187,7 @@ func TestNormalizeExtrinsic(t *testing.T) {
 		{
 			name: "Error Params",
 			args: args{
-				platform: Platform{CoinIndex: coin.KSM},
+				platform: Platform{CoinIndex: coin.KUSAMA},
 				srcTx: &Extrinsic{
 					Timestamp:          1577712822,
 					BlockNumber:        447444,
@@ -205,7 +205,7 @@ func TestNormalizeExtrinsic(t *testing.T) {
 		{
 			name: "set_heads",
 			args: args{
-				platform: Platform{CoinIndex: coin.KSM},
+				platform: Platform{CoinIndex: coin.KUSAMA},
 				srcTx: &Extrinsic{
 					Timestamp:          1577712822,
 					BlockNumber:        447444,
@@ -244,7 +244,7 @@ func TestNormalizeAddress(t *testing.T) {
 		{
 			name: "KSM address 1",
 			args: args{
-				platform: Platform{CoinIndex: coin.KSM},
+				platform: Platform{CoinIndex: coin.KUSAMA},
 				value:    "e8e1b8de72651640e302b62dad1f643ec8b65a3647a7409b2896634db599ed60",
 			},
 			wantAddress: "HqfgRXDgCQcV8KAuTAPGuA1r91iEzinmmNBPkR9kiKhifJq",
@@ -252,7 +252,7 @@ func TestNormalizeAddress(t *testing.T) {
 		{
 			name: "KSM address 2",
 			args: args{
-				platform: Platform{CoinIndex: coin.KSM},
+				platform: Platform{CoinIndex: coin.KUSAMA},
 				value:    "e0b3fcccfe0283cc0f8c105c68b5690aab8c5c1692a868e55eaca836c8779085",
 			},
 			wantAddress: "HewiDTQv92L2bVtkziZC8ASxrFUxr6ajQ62RXAnwQ8FDVmg",
@@ -260,7 +260,7 @@ func TestNormalizeAddress(t *testing.T) {
 		{
 			name: "DOT address",
 			args: args{
-				platform: Platform{CoinIndex: coin.DOT},
+				platform: Platform{CoinIndex: coin.POLKADOT},
 				value:    "e0b3fcccfe0283cc0f8c105c68b5690aab8c5c1692a868e55eaca836c8779085",
 			},
 			wantAddress: "165dCENc9ZGsiUgxwvxWSKdbfsxtrUqYMWymC9tC1gwGfATj",
diff --git a/platform/ripple/transaction_test.go b/platform/ripple/transaction_test.go
index 621981b..242a7d9 100644
--- a/platform/ripple/transaction_test.go
+++ b/platform/ripple/transaction_test.go
@@ -26,7 +26,7 @@ func TestNormalizeTx(t *testing.T) {
 			},
 			wantTx: types.Tx{
 				ID:     "40279A3DE51148BD41409DADF29DE8DCCD50F5AEE30840827B2C4C81C4E36505",
-				Coin:   coin.XRP,
+				Coin:   coin.RIPPLE,
 				From:   "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq",
 				To:     "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1",
 				Fee:    "3115",
@@ -49,7 +49,7 @@ func TestNormalizeTx(t *testing.T) {
 			},
 			wantTx: types.Tx{
 				ID:     "3D8512E02414EF5A6BC00281D945735E85DED9EF739B1DCA9EABE04D9EEC72C1",
-				Coin:   coin.XRP,
+				Coin:   coin.RIPPLE,
 				From:   "raz97dHvnyBcnYTbXGYxhV8bGyr1aPrE5w",
 				To:     "rna8qC8Y9uLd2vzYtSEa1AJcdD3896zQ9S",
 				Fee:    "120",
@@ -72,7 +72,7 @@ func TestNormalizeTx(t *testing.T) {
 			},
 			wantTx: types.Tx{
 				ID:     "B9086F7EB895E943C4DDA9F1B582E6E7DE35F4FB91AD13C50AB74F854DC0EBE0",
-				Coin:   coin.XRP,
+				Coin:   coin.RIPPLE,
 				From:   "rJb5KsHsDHF1YS5B5DU6QCkH5NsPaKQTcy",
 				To:     "rfHj5CuhajwdrzW2C8Y7EDXbx1QMiD5SXP",
 				Fee:    "100000",
diff --git a/platform/stellar/transaction_test.go b/platform/stellar/transaction_test.go
index e3045af..c25df6b 100644
--- a/platform/stellar/transaction_test.go
+++ b/platform/stellar/transaction_test.go
@@ -16,7 +16,7 @@ var (
 
 	createDst = types.Tx{
 		ID:    "8b96cf3a660b85ef80b5a84c032cacdb93bb139cfe7e929b974ea9eaa0d29141",
-		Coin:  coin.XLM,
+		Coin:  coin.STELLAR,
 		From:  "GBEZOC5U4TVH7ZY5N3FLYHTCZSI6VFGTULG7PBITLF5ZEBPJXFT46YZM",
 		To:    "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX",
 		Fee:   "100",
@@ -31,7 +31,7 @@ var (
 
 	transferDst = types.Tx{
 		ID:    "a596dc910bae20b5bbe64aa7aa3f42acbd55769b98307878f5ad095e994bc9cf",
-		Coin:  coin.XLM,
+		Coin:  coin.STELLAR,
 		From:  "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX",
 		To:    "GAX3BRBNB5WTJ2GNEFFH7A4CZKT2FORYABDDBZR5FIIT3P7FLS2EFOZZ",
 		Fee:   "100",
@@ -72,7 +72,7 @@ func testNormalize(t *testing.T, _test *test) {
 		t.Error(err)
 		return
 	}
-	tx, ok := Normalize(&payment, coin.XLM)
+	tx, ok := Normalize(&payment, coin.STELLAR)
 	if !ok {
 		t.Errorf("%s: tx could not be normalized", _test.name)
 	}
diff --git a/platform/tron/transaction_test.go b/platform/tron/transaction_test.go
index fccd80b..e193e5a 100644
--- a/platform/tron/transaction_test.go
+++ b/platform/tron/transaction_test.go
@@ -19,7 +19,7 @@ var (
 
 	transferDst = types.Tx{
 		ID:     "24a10f7a503e78adc0d7e380b68005531b09e16b9e3f7b524e33f40985d287df",
-		Coin:   coin.TRX,
+		Coin:   coin.TRON,
 		From:   "TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9",
 		To:     "TAUN6FwrnwwmaEqYcckffC7wYmbaS6cBiX",
 		Fee:    "0", // TODO
@@ -35,7 +35,7 @@ var (
 
 	tokenTransferDst = types.Tx{
 		ID:     "24a10f7a503e78adc0d7e380b68005531b09e16b9e3f7b524e33f40985d287df",
-		Coin:   coin.TRX,
+		Coin:   coin.TRON,
 		From:   "TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9",
 		To:     "TAUN6FwrnwwmaEqYcckffC7wYmbaS6cBiX",
 		Fee:    "0", // TODO
diff --git a/platform/vechain/transaction_test.go b/platform/vechain/transaction_test.go
index 87fdd96..1220a93 100644
--- a/platform/vechain/transaction_test.go
+++ b/platform/vechain/transaction_test.go
@@ -25,7 +25,7 @@ func TestNormalizeTransaction(t *testing.T) {
 	}{
 		{"Test normalize VET transfer transaction", "0xb5e883349e68ab59307d1604555ac890fac47128", transferSrc, trxId, types.Tx{
 			ID:        "0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7",
-			Coin:      coin.VET,
+			Coin:      coin.VECHAIN,
 			From:      "0xB5e883349e68aB59307d1604555AC890fAC47128",
 			To:        "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405",
 			Date:      1574410670,
@@ -73,7 +73,7 @@ func TestNormalizeTokenTransaction(t *testing.T) {
 		{"Normalize outgoing VTHO tx", "outgoing_vtho_tx.json", "outgoing_vtho_receipt.json", "0xe99399dd211eF54c301A5d1AA813471d92122eA8", types.TxPage{
 			{
 				ID:        "0x0677f91de4787d295087acec0a7ba317b0019fbf296fed630fdb5afbfca97a58",
-				Coin:      coin.VET,
+				Coin:      coin.VECHAIN,
 				From:      "0xe99399dd211eF54c301A5d1AA813471d92122eA8",
 				To:        "0x0000000000000000000000000000456E65726779",
 				Date:      1610958570,
@@ -96,7 +96,7 @@ func TestNormalizeTokenTransaction(t *testing.T) {
 		{"Normalize incoming VTHO tx", "incoming_vtho_tx.json", "incoming_vtho_receipt.json", "0xe99399dd211eF54c301A5d1AA813471d92122eA8", types.TxPage{
 			{
 				ID:        "0xb356fa7b3a371f1518a5f9bc51e951d0dac2ef04d58b532c7ca50a52aa5cddb4",
-				Coin:      coin.VET,
+				Coin:      coin.VECHAIN,
 				From:      "0xB5e883349e68aB59307d1604555AC890fAC47128",
 				To:        "0x0000000000000000000000000000456E65726779",
 				Date:      1610958460,
@@ -119,7 +119,7 @@ func TestNormalizeTokenTransaction(t *testing.T) {
 		{"Normalize reverted token transfer", "reverted_tx.json", "reverted_receipt.json", "0x7cFFB7632252Bae3766734d61F148f0Ea78Fc08C", types.TxPage{
 			{
 				ID:     "0x7fae32a743e42eaec54642e2a5742a185299f5b4bedaf12c60f65705661de932",
-				Coin:   coin.VET,
+				Coin:   coin.VECHAIN,
 				From:   "0x7cFFB7632252Bae3766734d61F148f0Ea78Fc08C",
 				To:     "0xf8e1fAa0367298b55F57Ed17F7a2FF3F5F1D1628",
 				Date:   1610326580,
diff --git a/platform/zilliqa/transaction_test.go b/platform/zilliqa/transaction_test.go
index cb52d33..f65f4cb 100644
--- a/platform/zilliqa/transaction_test.go
+++ b/platform/zilliqa/transaction_test.go
@@ -26,7 +26,7 @@ func TestNormalizeTx(t *testing.T) {
 			},
 			wantTx: types.Tx{
 				ID:       "0xd44413c79e7518152f3b05ef1edff8ef59afd06119b16d09c8bc72e94fed7843",
-				Coin:     coin.ZIL,
+				Coin:     coin.ZILLIQA,
 				From:     "0x88af5ba10796d9091d6893eed4db23ef0bbbca37",
 				To:       "0x7fccacf066a5f26ee3affc2ed1fa9810deaa632c",
 				Fee:      "1000000000",
diff --git a/services/notifier/models_test.go b/services/notifier/models_test.go
index ba1e106..ef62df7 100644
--- a/services/notifier/models_test.go
+++ b/services/notifier/models_test.go
@@ -12,7 +12,7 @@ import (
 var (
 	nativeTokenTransfer = types.Tx{
 		ID:     "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9",
-		Coin:   coin.BNB,
+		Coin:   coin.BINANCE,
 		From:   "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a",
 		To:     "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex",
 		Fee:    "125000",
@@ -52,7 +52,7 @@ var (
 	}
 	transfer = types.Tx{
 		ID:     "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44556",
-		Coin:   coin.BNB,
+		Coin:   coin.BINANCE,
 		From:   "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2",
 		To:     "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2",
 		Fee:    "125000",
@@ -68,7 +68,7 @@ var (
 	}
 	utxoTransfer = types.Tx{
 		ID:   "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC",
-		Coin: coin.BTC,
+		Coin: coin.BITCOIN,
 		Inputs: []types.TxOutput{
 			{
 				Address: "bc1qhn03cww757mnnlpkdvvfkaydxqygm86nvkm92h",