Repository: trustwallet/blockatlas
Pull request #860 (2020-02-14 03:43:35)

Remove unactive delegate only for stake list
# Headline

Remove inactive delegate only for stake list and keep to fetch  for delegations

## Issue

Validators can change the address or be outdated, but the user can already be staked in this validator

## Solution

Use the `disabled` flag to remove the validator from validator list, but we can show if we need to show delegation info for the user

closes https://github.com/trustwallet/blockatlas/issues/834

vikmeup: Thanks for clean PR, much easier to follow adjusted logic

Patch:
diff --git a/api/batch.go b/api/batch.go
index a6bebd7..9f511c8 100644
--- a/api/batch.go
+++ b/api/batch.go
@@ -33,7 +33,7 @@ type CoinsRequest []CoinBatchRequest
 // @Description Get Stake Delegations for multiple coins
 // @Accept json
 // @Produce json
-// @Tags Platform-Staking
+// @Tags Staking
 // @Param delegations body api.AddressesRequest true "Validators addresses and coins"
 // @Success 200 {object} blockatlas.DelegationsBatchPage
 // @Router /v2/staking/delegations [post]
@@ -70,7 +70,7 @@ func makeStakingDelegationsBatchRoute(router gin.IRouter) {
 // @Description Get Stake Delegations for multiple coins
 // @Accept json
 // @Produce json
-// @Tags Platform-Staking
+// @Tags Staking
 // @Param delegations body api.AddressesRequest true "Validators addresses and coins"
 // @Success 200 {object} blockatlas.DelegationsBatchPage
 // @Router /v2/staking/list [post]
@@ -104,7 +104,7 @@ func makeStakingDelegationsSimpleBatchRoute(router gin.IRouter) {
 // @Summary Get list of collections from a specific coin and addresses
 // @Accept json
 // @Produce json
-// @Tags Platform-Collections
+// @Tags Collections
 // @Param data body string true "Payload" default({"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]})
 // @Success 200 {object} blockatlas.DocsResponse
 // @Router /v2/collectibles/categories [post]
@@ -144,7 +144,7 @@ func oldMakeCategoriesBatchRoute(router gin.IRouter) {
 // @Summary Get list of collections from a specific coin and addresses
 // @Accept json
 // @Produce json
-// @Tags Platform-Collections
+// @Tags Collections
 // @Param data body string true "Payload" default({"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]})
 // @Success 200 {object} blockatlas.DocsResponse
 // @Router /v3/collectibles/categories [post]
diff --git a/api/handlers.go b/api/handlers.go
index faca610..03ba0e4 100644
--- a/api/handlers.go
+++ b/api/handlers.go
@@ -16,7 +16,7 @@ import (
 // @Description Get transactions from the address
 // @Accept json
 // @Produce json
-// @Tags Platform-Transactions
+// @Tags Transactions
 // @Param coin path string true "the coin name" default(tezos)
 // @Param address path string true "the query address" default(tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q)
 // @Failure 500 {object} ginutils.ApiError
@@ -30,7 +30,7 @@ func makeTxRouteV1(router gin.IRouter, api blockatlas.Platform) {
 // @Description Get transactions from the address
 // @Accept json
 // @Produce json
-// @Tags Platform-Transactions
+// @Tags Transactions
 // @Param coin path string true "the coin name" default(tezos)
 // @Param address path string true "the query address" default(tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q)
 // @Success 200 {object} blockatlas.TxPage
@@ -112,7 +112,7 @@ func makeTxRoute(router gin.IRouter, api blockatlas.Platform, path string) {
 // @Description Get all collections from the address
 // @Accept json
 // @Produce json
-// @Tags Platform-Collections
+// @Tags Collections
 // @Param coin path string true "the coin name" default(ethereum)
 // @Param address path string true "the query address" default(0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB)
 // @Success 200 {object} blockatlas.CollectionPage
@@ -143,7 +143,7 @@ func oldMakeCollectionsRoute(router gin.IRouter, api blockatlas.Platform) {
 // @Description Get all collections from the address
 // @Accept json
 // @Produce json
-// @Tags Platform-Collections
+// @Tags Collections
 // @Param coin path string true "the coin name" default(ethereum)
 // @Param address path string true "the query address" default(0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB)
 // @Success 200 {object} blockatlas.CollectionPage
@@ -173,7 +173,7 @@ func makeCollectionsRoute(router gin.IRouter, api blockatlas.Platform) {
 // @Description Get a collection from the address
 // @Accept json
 // @Produce json
-// @Tags Platform-Collections
+// @Tags Collections
 // @Param coin path string true "the coin name" default(ethereum)
 // @Param owner path string true "the query address" default(0x0875BCab22dE3d02402bc38aEe4104e1239374a7)
 // @Param collection_id path string true "the query collection" default(0x06012c8cf97bead5deae237070f9587f8e7a266d)
@@ -205,7 +205,7 @@ func oldMakeCollectionRoute(router gin.IRouter, api blockatlas.Platform) {
 // @Description Get a collection from the address
 // @Accept json
 // @Produce json
-// @Tags Platform-Collections
+// @Tags Collections
 // @Param coin path string true "the coin name" default(ethereum)
 // @Param owner path string true "the query address" default(0x0875BCab22dE3d02402bc38aEe4104e1239374a7)
 // @Param collection_id path string true "the query collection" default(0x06012c8cf97bead5deae237070f9587f8e7a266d)
@@ -236,7 +236,7 @@ func makeCollectionRoute(router gin.IRouter, api blockatlas.Platform) {
 // @Description Get tokens from the address
 // @Accept json
 // @Produce json
-// @Tags Platform-Transactions
+// @Tags Transactions
 // @Param coin path string true "the coin name" default(ethereum)
 // @Param address path string true "the query address" default(0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB)
 // @Success 200 {object} blockatlas.CollectionPage
diff --git a/api/naming_service.go b/api/naming_service.go
index a67506b..cd943e6 100644
--- a/api/naming_service.go
+++ b/api/naming_service.go
@@ -19,7 +19,7 @@ type LookupBatchPage []blockatlas.Resolved
 // @ID lookup
 // @Description Lookup ENS/ZNS to find registered addresses
 // @Produce json
-// @Tags Platform-Naming-Service
+// @Tags Naming
 // @Param name query string empty "string name"
 // @Param coin query string 60 "string coin"
 // @Success 200 {object} blockatlas.Resolved
@@ -52,7 +52,7 @@ func MakeLookupRoute(router gin.IRouter) {
 // @ID lookup
 // @Description Lookup ENS/ZNS to find registered addresses for multiple coins
 // @Produce json
-// @Tags Platform-Naming-Service
+// @Tags Naming
 // @Param name query string empty "string name"
 // @Param coins query string true "List of coins"
 // @Success 200 {array} blockatlas.Resolved
diff --git a/api/stake.go b/api/stake.go
index a350a6c..f691669 100644
--- a/api/stake.go
+++ b/api/stake.go
@@ -16,7 +16,7 @@ import (
 // @Description Get validators from the address
 // @Accept json
 // @Produce json
-// @Tags Platform-Staking
+// @Tags Staking
 // @Param coin path string true "the coin name" default(cosmos)
 // @Success 200 {object} blockatlas.DocsResponse
 // @Failure 500 {object} ginutils.ApiError
@@ -30,7 +30,7 @@ func makeStakingValidatorsRoute(router gin.IRouter, api blockatlas.Platform) {
 	}
 
 	router.GET("/staking/validators", gincache.CacheMiddleware(time.Hour, func(c *gin.Context) {
-		results, err := services.GetValidators(stakingAPI)
+		results, err := services.GetActiveValidators(stakingAPI)
 		if err != nil {
 			logger.Error(err)
 			ginutils.ErrorResponse(c).Message(err.Error()).Render()
@@ -45,7 +45,7 @@ func makeStakingValidatorsRoute(router gin.IRouter, api blockatlas.Platform) {
 // @Description Get stake delegations from the address
 // @Accept json
 // @Produce json
-// @Tags Platform-Staking
+// @Tags Staking
 // @Param coin path string true "the coin name" default(tron)
 // @Param address path string true "the query address" default(TPJYCz8ppZNyvw7pTwmjajcx4Kk1MmEUhD)
 // @Success 200 {object} blockatlas.DelegationResponse
diff --git a/docs/docs.go b/docs/docs.go
index b3327af..e52d2c0 100644
--- a/docs/docs.go
+++ b/docs/docs.go
@@ -1,6 +1,6 @@
 // GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 // This file was generated by swaggo/swag at
-// 2020-02-13 21:02:22.715378 -0700 MST m=+0.143781826
+// 2020-02-14 14:10:03.328765 -0700 MST m=+0.094246342
 
 package docs
 
@@ -33,7 +33,7 @@ var doc = `{
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Naming-Service"
+                    "Naming"
                 ],
                 "summary": "Lookup .eth / .zil addresses",
                 "operationId": "lookup",
@@ -389,7 +389,7 @@ var doc = `{
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Transactions"
+                    "Transactions"
                 ],
                 "summary": "Get xpub transactions",
                 "operationId": "xpub",
@@ -431,7 +431,7 @@ var doc = `{
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Transactions"
+                    "Transactions"
                 ],
                 "summary": "Get Transactions",
                 "operationId": "tx_v1",
@@ -473,7 +473,7 @@ var doc = `{
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Collections"
+                    "Collections"
                 ],
                 "summary": "Get list of collections from a specific coin and addresses",
                 "operationId": "collection_categories_v2",
@@ -506,7 +506,7 @@ var doc = `{
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Naming-Service"
+                    "Naming"
                 ],
                 "summary": "Lookup .eth / .zil addresses",
                 "operationId": "lookup",
@@ -554,7 +554,7 @@ var doc = `{
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Staking"
+                    "Staking"
                 ],
                 "summary": "Get Multiple Stake Delegations",
                 "operationId": "batch_delegations",
@@ -589,7 +589,7 @@ var doc = `{
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Staking"
+                    "Staking"
                 ],
                 "summary": "Get Multiple Stake Delegations",
                 "operationId": "batch_delegations",
@@ -624,7 +624,7 @@ var doc = `{
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Collections"
+                    "Collections"
                 ],
                 "summary": "Get Collections",
                 "operationId": "collections_v2",
@@ -672,7 +672,7 @@ var doc = `{
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Collections"
+                    "Collections"
                 ],
                 "summary": "Get Collection",
                 "operationId": "collection_v2",
@@ -728,7 +728,7 @@ var doc = `{
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Staking"
+                    "Staking"
                 ],
                 "summary": "Get Stake Delegations",
                 "operationId": "delegations",
@@ -776,7 +776,7 @@ var doc = `{
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Staking"
+                    "Staking"
                 ],
                 "summary": "Get Validators",
                 "operationId": "validators",
@@ -816,7 +816,7 @@ var doc = `{
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Transactions"
+                    "Transactions"
                 ],
                 "summary": "Get Tokens",
                 "operationId": "tokens",
@@ -864,7 +864,7 @@ var doc = `{
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Transactions"
+                    "Transactions"
                 ],
                 "summary": "Get Transactions",
                 "operationId": "tx_v2",
@@ -912,7 +912,7 @@ var doc = `{
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Collections"
+                    "Collections"
                 ],
                 "summary": "Get list of collections from a specific coin and addresses",
                 "operationId": "collection_categories_v3",
@@ -948,7 +948,7 @@ var doc = `{
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Collections"
+                    "Collections"
                 ],
                 "summary": "Get Collections",
                 "operationId": "collections_v3",
@@ -996,7 +996,7 @@ var doc = `{
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Collections"
+                    "Collections"
                 ],
                 "summary": "Get Collection",
                 "operationId": "collection_v3",
diff --git a/docs/swagger.json b/docs/swagger.json
index dbdec9b..fce62e6 100644
--- a/docs/swagger.json
+++ b/docs/swagger.json
@@ -12,7 +12,7 @@
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Naming-Service"
+                    "Naming"
                 ],
                 "summary": "Lookup .eth / .zil addresses",
                 "operationId": "lookup",
@@ -368,7 +368,7 @@
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Transactions"
+                    "Transactions"
                 ],
                 "summary": "Get xpub transactions",
                 "operationId": "xpub",
@@ -410,7 +410,7 @@
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Transactions"
+                    "Transactions"
                 ],
                 "summary": "Get Transactions",
                 "operationId": "tx_v1",
@@ -452,7 +452,7 @@
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Collections"
+                    "Collections"
                 ],
                 "summary": "Get list of collections from a specific coin and addresses",
                 "operationId": "collection_categories_v2",
@@ -485,7 +485,7 @@
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Naming-Service"
+                    "Naming"
                 ],
                 "summary": "Lookup .eth / .zil addresses",
                 "operationId": "lookup",
@@ -533,7 +533,7 @@
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Staking"
+                    "Staking"
                 ],
                 "summary": "Get Multiple Stake Delegations",
                 "operationId": "batch_delegations",
@@ -568,7 +568,7 @@
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Staking"
+                    "Staking"
                 ],
                 "summary": "Get Multiple Stake Delegations",
                 "operationId": "batch_delegations",
@@ -603,7 +603,7 @@
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Collections"
+                    "Collections"
                 ],
                 "summary": "Get Collections",
                 "operationId": "collections_v2",
@@ -651,7 +651,7 @@
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Collections"
+                    "Collections"
                 ],
                 "summary": "Get Collection",
                 "operationId": "collection_v2",
@@ -707,7 +707,7 @@
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Staking"
+                    "Staking"
                 ],
                 "summary": "Get Stake Delegations",
                 "operationId": "delegations",
@@ -755,7 +755,7 @@
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Staking"
+                    "Staking"
                 ],
                 "summary": "Get Validators",
                 "operationId": "validators",
@@ -795,7 +795,7 @@
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Transactions"
+                    "Transactions"
                 ],
                 "summary": "Get Tokens",
                 "operationId": "tokens",
@@ -843,7 +843,7 @@
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Transactions"
+                    "Transactions"
                 ],
                 "summary": "Get Transactions",
                 "operationId": "tx_v2",
@@ -891,7 +891,7 @@
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Collections"
+                    "Collections"
                 ],
                 "summary": "Get list of collections from a specific coin and addresses",
                 "operationId": "collection_categories_v3",
@@ -927,7 +927,7 @@
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Collections"
+                    "Collections"
                 ],
                 "summary": "Get Collections",
                 "operationId": "collections_v3",
@@ -975,7 +975,7 @@
                     "application/json"
                 ],
                 "tags": [
-                    "Platform-Collections"
+                    "Collections"
                 ],
                 "summary": "Get Collection",
                 "operationId": "collection_v3",
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
index 4c0fb07..660b54e 100644
--- a/docs/swagger.yaml
+++ b/docs/swagger.yaml
@@ -404,7 +404,7 @@ paths:
             $ref: '#/definitions/ginutils.ApiError'
       summary: Lookup .eth / .zil addresses
       tags:
-      - Platform-Naming-Service
+      - Naming
   /observer/v1/status:
     get:
       consumes:
@@ -513,7 +513,7 @@ paths:
             $ref: '#/definitions/ginutils.ApiError'
       summary: Get Transactions
       tags:
-      - Platform-Transactions
+      - Transactions
   /v1/{coin}/xpub/{xpub}:
     get:
       consumes:
@@ -542,7 +542,7 @@ paths:
             $ref: '#/definitions/blockatlas.TxPage'
       summary: Get xpub transactions
       tags:
-      - Platform-Transactions
+      - Transactions
   /v1/market/charts:
     get:
       consumes:
@@ -707,7 +707,7 @@ paths:
             $ref: '#/definitions/ginutils.ApiError'
       summary: Get Collections
       tags:
-      - Platform-Collections
+      - Collections
   /v2/{coin}/collections/{owner}/collection/{collection_id}:
     get:
       consumes:
@@ -746,7 +746,7 @@ paths:
             $ref: '#/definitions/ginutils.ApiError'
       summary: Get Collection
       tags:
-      - Platform-Collections
+      - Collections
   /v2/{coin}/staking/delegations/{address}:
     get:
       consumes:
@@ -779,7 +779,7 @@ paths:
             $ref: '#/definitions/ginutils.ApiError'
       summary: Get Stake Delegations
       tags:
-      - Platform-Staking
+      - Staking
   /v2/{coin}/staking/validators:
     get:
       consumes:
@@ -806,7 +806,7 @@ paths:
             $ref: '#/definitions/ginutils.ApiError'
       summary: Get Validators
       tags:
-      - Platform-Staking
+      - Staking
   /v2/{coin}/tokens/{address}:
     get:
       consumes:
@@ -839,7 +839,7 @@ paths:
             $ref: '#/definitions/ginutils.ApiError'
       summary: Get Tokens
       tags:
-      - Platform-Transactions
+      - Transactions
   /v2/{coin}/transactions/{address}:
     get:
       consumes:
@@ -872,7 +872,7 @@ paths:
             $ref: '#/definitions/ginutils.ApiError'
       summary: Get Transactions
       tags:
-      - Platform-Transactions
+      - Transactions
   /v2/collectibles/categories:
     post:
       consumes:
@@ -896,7 +896,7 @@ paths:
             $ref: '#/definitions/blockatlas.DocsResponse'
       summary: Get list of collections from a specific coin and addresses
       tags:
-      - Platform-Collections
+      - Collections
   /v2/ns/lookup:
     get:
       description: Lookup ENS/ZNS to find registered addresses for multiple coins
@@ -926,7 +926,7 @@ paths:
             $ref: '#/definitions/ginutils.ApiError'
       summary: Lookup .eth / .zil addresses
       tags:
-      - Platform-Naming-Service
+      - Naming
   /v2/staking/delegations:
     post:
       consumes:
@@ -949,7 +949,7 @@ paths:
             $ref: '#/definitions/blockatlas.DelegationsBatchPage'
       summary: Get Multiple Stake Delegations
       tags:
-      - Platform-Staking
+      - Staking
   /v2/staking/list:
     post:
       consumes:
@@ -972,7 +972,7 @@ paths:
             $ref: '#/definitions/blockatlas.DelegationsBatchPage'
       summary: Get Multiple Stake Delegations
       tags:
-      - Platform-Staking
+      - Staking
   /v3/{coin}/collections/{address}:
     get:
       consumes:
@@ -1005,7 +1005,7 @@ paths:
             $ref: '#/definitions/ginutils.ApiError'
       summary: Get Collections
       tags:
-      - Platform-Collections
+      - Collections
   /v3/{coin}/collections/{owner}/collection/{collection_id}:
     get:
       consumes:
@@ -1044,7 +1044,7 @@ paths:
             $ref: '#/definitions/ginutils.ApiError'
       summary: Get Collection
       tags:
-      - Platform-Collections
+      - Collections
   /v3/collectibles/categories:
     post:
       consumes:
@@ -1068,5 +1068,5 @@ paths:
             $ref: '#/definitions/blockatlas.DocsResponse'
       summary: Get list of collections from a specific coin and addresses
       tags:
-      - Platform-Collections
+      - Collections
 swagger: "2.0"
diff --git a/platform/bitcoin/api.go b/platform/bitcoin/api.go
index 1167783..7b89ee6 100644
--- a/platform/bitcoin/api.go
+++ b/platform/bitcoin/api.go
@@ -36,7 +36,7 @@ func (p *Platform) ConfigKey() string {
 // @Description Get transactions from xpub address
 // @Accept json
 // @Produce json
-// @Tags Platform-Transactions
+// @Tags Transactions
 // @Param coin path string true "the coin name" default(bitcoin)
 // @Param xpub path string true "the xpub address" default(zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC)
 // @Success 200 {object} blockatlas.TxPage
diff --git a/platform/ripple/api.go b/platform/ripple/api.go
index 0a1e276..9397e87 100644
--- a/platform/ripple/api.go
+++ b/platform/ripple/api.go
@@ -68,12 +68,9 @@ func NormalizeTxs(srcTxs []Tx) (txs []blockatlas.Tx) {
 
 // Normalize converts a Ripple transaction into the generic model
 func NormalizeTx(srcTx *Tx) (blockatlas.Tx, bool) {
-
+	unix := int64(0)
 	date, err := time.Parse("2006-01-02T15:04:05-07:00", srcTx.Date)
-	var unix int64
-	if err != nil {
-		unix = 0
-	} else {
+	if err == nil {
 		unix = date.Unix()
 	}
 
@@ -82,18 +79,24 @@ func NormalizeTx(srcTx *Tx) (blockatlas.Tx, bool) {
 		return blockatlas.Tx{}, false
 	}
 
-	if srcTx.Payment.TransactionType != "Payment" {
+	if srcTx.Payment.TransactionType != transactionPayment {
 		return blockatlas.Tx{}, false
 	}
 
+	status := blockatlas.StatusCompleted
+	if srcTx.Meta.TransactionResult != transactionResultSuccess {
+		status = blockatlas.StatusFailed
+	}
+
 	result := blockatlas.Tx{
-		ID:    srcTx.Hash,
-		Coin:  coin.XRP,
-		Date:  unix,
-		From:  srcTx.Payment.Account,
-		To:    srcTx.Payment.Destination,
-		Fee:   srcTx.Payment.Fee,
-		Block: srcTx.LedgerIndex,
+		ID:     srcTx.Hash,
+		Coin:   coin.XRP,
+		Date:   unix,
+		From:   srcTx.Payment.Account,
+		To:     srcTx.Payment.Destination,
+		Fee:    srcTx.Payment.Fee,
+		Block:  srcTx.LedgerIndex,
+		Status: status,
 		Meta: blockatlas.Transfer{
 			Value:    blockatlas.Amount(v),
 			Symbol:   coin.Coins[coin.XRP].Symbol,
diff --git a/platform/ripple/client.go b/platform/ripple/client.go
index f4007c1..5e8ec70 100644
--- a/platform/ripple/client.go
+++ b/platform/ripple/client.go
@@ -12,9 +12,9 @@ type Client struct {
 
 func (c *Client) GetTxsOfAddress(address string) ([]Tx, error) {
 	query := url.Values{
-		"type":   {"Payment"},
-		"result": {"tesSUCCESS"},
-		"limit":  {"200"},
+		"type":       {"Payment"},
+		"descending": {"true"},
+		"limit":      {"200"},
 	}
 	uri := fmt.Sprintf("accounts/%s/transactions", url.PathEscape(address))
 
diff --git a/platform/ripple/model.go b/platform/ripple/model.go
index 18c5428..af5101e 100644
--- a/platform/ripple/model.go
+++ b/platform/ripple/model.go
@@ -4,6 +4,15 @@ import (
 	"github.com/trustwallet/blockatlas/pkg/blockatlas"
 )
 
+type TransactionType string
+type TransactionResult string
+
+const (
+	transactionResultSuccess TransactionResult = "tesSUCCESS"
+
+	transactionPayment TransactionType = "Payment"
+)
+
 type Response struct {
 	Result       string `json:"result"`
 	Count        uint64 `json:"count"`
@@ -21,7 +30,7 @@ type Tx struct {
 }
 
 type Payment struct {
-	TransactionType string            `json:"TransactionType"`
+	TransactionType TransactionType   `json:"TransactionType"`
 	Flags           uint64            `json:"Flags"`
 	Sequence        uint64            `json:"Sequence"`
 	Fee             blockatlas.Amount `json:"Fee"`
@@ -33,7 +42,8 @@ type Payment struct {
 }
 
 type Meta struct {
-	DeliveredAmount interface{} `json:"delivered_amount,omitempty"`
+	TransactionResult TransactionResult `json:"TransactionResult,omitempty"`
+	DeliveredAmount   interface{}       `json:"delivered_amount,omitempty"`
 }
 
 type DeliveredAmount struct {
diff --git a/services/assets/model.go b/services/assets/model.go
index f9b7ff4..1eed6ee 100644
--- a/services/assets/model.go
+++ b/services/assets/model.go
@@ -27,3 +27,13 @@ func (av AssetValidators) toMap() AssetValidatorMap {
 	}
 	return validators
 }
+
+func (av AssetValidators) activeValidators() AssetValidators {
+	activeAssets := make(AssetValidators, 0)
+	for _, a := range av {
+		if !a.Status.Disabled {
+			activeAssets = append(activeAssets, a)
+		}
+	}
+	return activeAssets
+}
diff --git a/services/assets/stake.go b/services/assets/stake.go
index 0b1e102..6c5999d 100644
--- a/services/assets/stake.go
+++ b/services/assets/stake.go
@@ -23,40 +23,50 @@ func requestValidatorsInfo(coin coin.Coin) (AssetValidators, error) {
 }
 
 func GetValidatorsMap(api blockatlas.StakeAPI) (blockatlas.ValidatorMap, error) {
-	validators, err := GetValidators(api)
+	assets, validators, err := GetValidators(api)
 	if err != nil {
 		return nil, err
 	}
-	return validators.ToMap(), nil
+	results := normalizeValidators(assets, validators, api.Coin())
+	return results.ToMap(), nil
 }
 
-func GetValidators(api blockatlas.StakeAPI) (blockatlas.StakeValidators, error) {
+func GetActiveValidators(api blockatlas.StakeAPI) (blockatlas.StakeValidators, error) {
+	assets, validators, err := GetValidators(api)
+	if err != nil {
+		return nil, err
+	}
+	results := normalizeValidators(assets.activeValidators(), validators, api.Coin())
+	return results, nil
+}
+
+func GetValidators(api blockatlas.StakeAPI) (AssetValidators, blockatlas.ValidatorPage, error) {
 	assetsValidators, err := requestValidatorsInfo(api.Coin())
 	if err != nil {
-		return nil, errors.E(err, "unable to fetch validators list from the registry").PushToSentry()
+		return nil, nil, errors.E(err, "unable to fetch validators list from the registry").PushToSentry()
 	}
 
 	validators, err := api.GetValidators()
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
-	results := normalizeValidators(validators, assetsValidators, api.Coin())
-	sort.Slice(results, func(i, j int) bool {
-		return results[i].Details.Reward.Annual > results[j].Details.Reward.Annual
-	})
-	return results, nil
+	return assetsValidators, validators, nil
 }
 
-func normalizeValidators(validators []blockatlas.Validator, assets AssetValidators, coin coin.Coin) blockatlas.StakeValidators {
+func normalizeValidators(assets AssetValidators, validators []blockatlas.Validator, coin coin.Coin) blockatlas.StakeValidators {
 	results := make(blockatlas.StakeValidators, 0)
 	assetsMap := assets.toMap()
 	for _, v := range validators {
 		asset, ok := assetsMap[v.ID]
-		if !ok || asset.Status.Disabled {
+		if !ok {
 			continue
 		}
 		results = append(results, normalizeValidator(v, asset, coin))
 	}
+
+	sort.Slice(results, func(i, j int) bool {
+		return results[i].Details.Reward.Annual > results[j].Details.Reward.Annual
+	})
 	return results
 }
 
@@ -65,7 +75,7 @@ func normalizeValidator(plainValidator blockatlas.Validator, validator AssetVali
 	details.Reward.Annual = calculateAnnual(details.Reward.Annual, validator.Payout.Commission)
 	return blockatlas.StakeValidator{
 		ID:     validator.ID,
-		Status: plainValidator.Status,
+		Status: plainValidator.Status && !validator.Status.Disabled,
 		Info: blockatlas.StakeValidatorInfo{
 			Name:        validator.Name,
 			Description: validator.Description,
@@ -75,7 +85,6 @@ func normalizeValidator(plainValidator blockatlas.Validator, validator AssetVali
 		Details: details,
 	}
 }
-
 func calculateAnnual(annual float64, commission float64) float64 {
 	return (annual * (100 - commission)) / 100
 }


Test patch:
diff --git a/platform/ripple/api_test.go b/platform/ripple/api_test.go
index e2f7549..ef640be 100644
--- a/platform/ripple/api_test.go
+++ b/platform/ripple/api_test.go
@@ -44,14 +44,15 @@ const paymentSrc = `
 `
 
 var paymentDst = blockatlas.Tx{
-	ID:    "40279A3DE51148BD41409DADF29DE8DCCD50F5AEE30840827B2C4C81C4E36505",
-	Coin:  coin.XRP,
-	From:  "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq",
-	To:    "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1",
-	Fee:   "3115",
-	Date:  1512168330,
-	Block: 34698103,
-	Memo:  "2500",
+	ID:     "40279A3DE51148BD41409DADF29DE8DCCD50F5AEE30840827B2C4C81C4E36505",
+	Coin:   coin.XRP,
+	From:   "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq",
+	To:     "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1",
+	Fee:    "3115",
+	Date:   1512168330,
+	Block:  34698103,
+	Memo:   "2500",
+	Status: blockatlas.StatusCompleted,
 	Meta: blockatlas.Transfer{
 		Value:    "100000000",
 		Symbol:   "XRP",
@@ -100,14 +101,15 @@ const paymentSrc2 = `
 `
 
 var paymentDst2 = blockatlas.Tx{
-	ID:    "3D8512E02414EF5A6BC00281D945735E85DED9EF739B1DCA9EABE04D9EEC72C1",
-	Coin:  coin.XRP,
-	From:  "raz97dHvnyBcnYTbXGYxhV8bGyr1aPrE5w",
-	To:    "rna8qC8Y9uLd2vzYtSEa1AJcdD3896zQ9S",
-	Fee:   "120",
-	Date:  1565114281,
-	Block: 49163909,
-	Memo:  "",
+	ID:     "3D8512E02414EF5A6BC00281D945735E85DED9EF739B1DCA9EABE04D9EEC72C1",
+	Coin:   coin.XRP,
+	From:   "raz97dHvnyBcnYTbXGYxhV8bGyr1aPrE5w",
+	To:     "rna8qC8Y9uLd2vzYtSEa1AJcdD3896zQ9S",
+	Fee:    "120",
+	Date:   1565114281,
+	Block:  49163909,
+	Memo:   "",
+	Status: blockatlas.StatusCompleted,
 	Meta: blockatlas.Transfer{
 		Value:    "3100",
 		Symbol:   "XRP",
@@ -163,6 +165,48 @@ const paymentSrc4 = `
 }
 `
 
+const failedPayment = `
+{
+  "hash": "B9086F7EB895E943C4DDA9F1B582E6E7DE35F4FB91AD13C50AB74F854DC0EBE0",
+  "ledger_index": 53401154,
+  "date": "2020-02-13T10:47:52+00:00",
+  "tx": {
+    "TransactionType": "Payment",
+    "Flags": 2147483648,
+    "Sequence": 2102726,
+    "LastLedgerSequence": 53401182,
+    "Amount": "24999750000",
+    "Fee": "100000",
+    "SigningPubKey": "02C2EDA75565BA8D3CBD96FB28D53C9BE1B7A4DC1AF6FF1B2EBBD478D520BED52E",
+    "TxnSignature": "304502210081A1620F2106671FDFB9C0ABEB2976236693E6142E2B4CB7EA89338EA344BF8D02200EC9D2E2BE79C9E053F809802C426AFDC55B7BA5E01E3DF4B193F122740C39A3",
+    "Account": "rJb5KsHsDHF1YS5B5DU6QCkH5NsPaKQTcy",
+    "Destination": "rfHj5CuhajwdrzW2C8Y7EDXbx1QMiD5SXP"
+  },
+  "meta": {
+    "TransactionIndex": 30,
+    "TransactionResult": "tefBAD_LEDGER",
+    "delivered_amount": "24999750000"
+  }
+}
+`
+
+var failedPaymentDst = blockatlas.Tx{
+	ID:     "B9086F7EB895E943C4DDA9F1B582E6E7DE35F4FB91AD13C50AB74F854DC0EBE0",
+	Coin:   coin.XRP,
+	From:   "rJb5KsHsDHF1YS5B5DU6QCkH5NsPaKQTcy",
+	To:     "rfHj5CuhajwdrzW2C8Y7EDXbx1QMiD5SXP",
+	Fee:    "100000",
+	Date:   1581590872,
+	Block:  53401154,
+	Memo:   "",
+	Status: blockatlas.StatusFailed,
+	Meta: blockatlas.Transfer{
+		Value:    "24999750000",
+		Symbol:   "XRP",
+		Decimals: 6,
+	},
+}
+
 type test struct {
 	name        string
 	apiResponse string
@@ -177,27 +221,30 @@ func TestNormalize(t *testing.T) {
 		expected:    paymentDst,
 		normalize:   true,
 	})
-
 	testNormalize(t, &test{
 		name:        "payment 2",
 		apiResponse: paymentSrc2,
 		expected:    paymentDst2,
 		normalize:   true,
 	})
-
 	testNormalize(t, &test{
 		name:        "SetRegularKey transfer",
 		apiResponse: paymentSrc3,
 		expected:    blockatlas.Tx{},
 		normalize:   false,
 	})
-
 	testNormalize(t, &test{
 		name:        "token transfer",
 		apiResponse: paymentSrc4,
 		expected:    blockatlas.Tx{},
 		normalize:   false,
 	})
+	testNormalize(t, &test{
+		name:        "failed payment",
+		apiResponse: failedPayment,
+		expected:    failedPaymentDst,
+		normalize:   true,
+	})
 }
 
 func testNormalize(t *testing.T, _test *test) {
diff --git a/services/assets/model_test.go b/services/assets/model_test.go
index 9b02573..0145819 100644
--- a/services/assets/model_test.go
+++ b/services/assets/model_test.go
@@ -1,7 +1,7 @@
 package assets
 
 import (
-	"reflect"
+	"github.com/stretchr/testify/assert"
 	"testing"
 )
 
@@ -17,9 +17,38 @@ func TestAssetValidators_toMap(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			if got := tt.av.toMap(); !reflect.DeepEqual(got, tt.want) {
-				t.Errorf("toMap() = %v, want %v", got, tt.want)
-			}
+			got := tt.av.toMap()
+			assert.Equal(t, tt.want, got)
+		})
+	}
+}
+
+func TestAssetValidators_activeValidators(t *testing.T) {
+	tests := []struct {
+		name string
+		av   AssetValidators
+		want AssetValidators
+	}{
+		{
+			"test get active validators 1",
+			AssetValidators{{ID: "test1", Status: ValidatorStatus{false}}},
+			AssetValidators{{ID: "test1", Status: ValidatorStatus{false}}},
+		},
+		{
+			"test get active validators 2",
+			AssetValidators{{ID: "test1", Status: ValidatorStatus{true}}},
+			AssetValidators{},
+		},
+		{
+			"test get active validators 3",
+			AssetValidators{{ID: "test1", Status: ValidatorStatus{true}}, {ID: "test2", Status: ValidatorStatus{false}}},
+			AssetValidators{{ID: "test2", Status: ValidatorStatus{false}}},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := tt.av.activeValidators()
+			assert.Equal(t, tt.want, got)
 		})
 	}
 }
diff --git a/services/assets/stake_test.go b/services/assets/stake_test.go
index 1ac838f..40ca40a 100644
--- a/services/assets/stake_test.go
+++ b/services/assets/stake_test.go
@@ -7,35 +7,78 @@ import (
 	"testing"
 )
 
-var cosmosCoin = coin.Coin{Handle: "cosmos"}
-var validators = []blockatlas.Validator{
-	{
-		ID:     "test",
-		Status: true,
-	},
-	{
-		ID:     "test2",
-		Status: true,
-	},
-}
-var assets = []AssetValidator{
-	{
-		ID:          "test",
-		Name:        "Spider",
-		Description: "yo",
-		Website:     "https://tw.com",
-	},
-}
-
-var expectedStakeValidator = blockatlas.StakeValidator{
-	ID: "test", Status: true,
-	Info: blockatlas.StakeValidatorInfo{
-		Name:        "Spider",
-		Description: "yo",
-		Image:       "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/cosmos/validators/assets/test/logo.png",
-		Website:     "https://tw.com",
-	},
-}
+var (
+	cosmosCoin = coin.Coin{Handle: "cosmos"}
+	validators = []blockatlas.Validator{
+		{
+			ID:     "test1",
+			Status: true,
+		},
+		{
+			ID:     "test2",
+			Status: true,
+		},
+	}
+	assets1 = []AssetValidator{
+		{
+			ID:          "test1",
+			Name:        "Spider",
+			Description: "yo",
+			Website:     "https://tw.com",
+			Status:      ValidatorStatus{Disabled: false},
+		},
+		{
+			ID:          "test2",
+			Name:        "Man",
+			Description: "lo",
+			Website:     "https://tw.com",
+			Status:      ValidatorStatus{Disabled: true},
+		},
+	}
+	assets2 = []AssetValidator{
+		{
+			ID:          "test1",
+			Name:        "Spider",
+			Description: "yo",
+			Website:     "https://tw.com",
+			Status:      ValidatorStatus{Disabled: true},
+		},
+		{
+			ID:          "test2",
+			Name:        "Man",
+			Description: "lo",
+			Website:     "https://tw.com",
+			Status:      ValidatorStatus{Disabled: true},
+		},
+	}
+	expectedStakeValidator = blockatlas.StakeValidator{
+		ID: "test1", Status: true,
+		Info: blockatlas.StakeValidatorInfo{
+			Name:        "Spider",
+			Description: "yo",
+			Image:       "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/cosmos/validators/assets/test1/logo.png",
+			Website:     "https://tw.com",
+		},
+	}
+	expectedStakeValidatorDisabled1 = blockatlas.StakeValidator{
+		ID: "test1", Status: false,
+		Info: blockatlas.StakeValidatorInfo{
+			Name:        "Spider",
+			Description: "yo",
+			Image:       "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/cosmos/validators/assets/test1/logo.png",
+			Website:     "https://tw.com",
+		},
+	}
+	expectedStakeValidatorDisabled2 = blockatlas.StakeValidator{
+		ID: "test2", Status: false,
+		Info: blockatlas.StakeValidatorInfo{
+			Name:        "Man",
+			Description: "lo",
+			Image:       "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/cosmos/validators/assets/test2/logo.png",
+			Website:     "https://tw.com",
+		},
+	}
+)
 
 func TestGetImage(t *testing.T) {
 	image := getImage(cosmosCoin, "TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp")
@@ -43,17 +86,6 @@ func TestGetImage(t *testing.T) {
 	assert.Equal(t, expected, image)
 }
 
-func TestNormalizeValidator(t *testing.T) {
-	result := normalizeValidator(validators[0], assets[0], cosmosCoin)
-	assert.Equal(t, expectedStakeValidator, result)
-}
-
-func TestNormalizeValidators(t *testing.T) {
-	result := normalizeValidators(validators, assets, cosmosCoin)
-	expected := blockatlas.StakeValidators{expectedStakeValidator}
-	assert.Equal(t, expected, result)
-}
-
 func TestCalcAnnual(t *testing.T) {
 	type args struct {
 		annual     float64
@@ -106,3 +138,30 @@ func TestCalcAnnual(t *testing.T) {
 		})
 	}
 }
+
+func TestNormalizeValidator(t *testing.T) {
+	result := normalizeValidator(validators[0], assets1[0], cosmosCoin)
+	assert.Equal(t, expectedStakeValidator, result)
+}
+
+func Test_normalizeValidators(t *testing.T) {
+	type args struct {
+		assets     AssetValidators
+		validators []blockatlas.Validator
+		coin       coin.Coin
+	}
+	tests := []struct {
+		name string
+		args args
+		want blockatlas.StakeValidators
+	}{
+		{"normalize validator 1", args{assets1, validators, cosmosCoin}, blockatlas.StakeValidators{expectedStakeValidator, expectedStakeValidatorDisabled2}},
+		{"normalize validator 2", args{assets2, validators, cosmosCoin}, blockatlas.StakeValidators{expectedStakeValidatorDisabled1, expectedStakeValidatorDisabled2}},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := normalizeValidators(tt.args.assets, tt.args.validators, tt.args.coin)
+			assert.Equal(t, tt.want, got)
+		})
+	}
+}